/*
  Copyright (c) 2010, Nicolas Garcia Belmonte
  All rights reserved

  > Redistribution and use in source and binary forms, with or without
  > modification, are permitted provided that the following conditions are met:
  >      * Redistributions of source code must retain the above copyright
  >        notice, this list of conditions and the following disclaimer.
  >      * Redistributions in binary form must reproduce the above copyright
  >        notice, this list of conditions and the following disclaimer in the
  >        documentation and/or other materials provided with the distribution.
  >      * Neither the name of the organization nor the
  >        names of its contributors may be used to endorse or promote products
  >        derived from this software without specific prior written permission.
  >
  >  THIS SOFTWARE IS PROVIDED BY NICOLAS GARCIA BELMONTE ``AS IS'' AND ANY
  >  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  >  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  >  DISCLAIMED. IN NO EVENT SHALL NICOLAS GARCIA BELMONTE BE LIABLE FOR ANY
  >  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  >  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  >  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  >  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  >  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  >  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
(function() {
    window.$jit = function(x) {
        x = x || window;
        for (var y in $jit) {
            if ($jit[y].$extend) {
                x[y] = $jit[y]
            }
        }
    };
    $jit.version = "2.0.0b";
    var c = function(w) {
        return document.getElementById(w)
    };
    c.empty = function() {};
    c.extend = function(y, w) {
        for (var x in (w || {})) {
            y[x] = w[x]
        }
        return y
    };
    c.lambda = function(w) {
        return (typeof w == "function") ? w: function() {
            return w
        }
    };
    c.time = Date.now ||
    function() {
        return + new Date
    };
    c.splat = function(x) {
        var w = c.type(x);
        return w ? ((w != "array") ? [x] : x) : []
    };
    c.type = function(x) {
        var w = c.type.s.call(x).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
        if (w != "object") {
            return w
        }
        if (x && x.$$family) {
            return x.$$family
        }
        return (x && x.nodeName && x.nodeType == 1) ? "element": w
    };
    c.type.s = Object.prototype.toString;
    c.each = function(B, A) {
        var z = c.type(B);
        if (z == "object") {
            for (var y in B) {
                A(B[y], y)
            }
        } else {
            for (var x = 0,
            w = B.length; x < w; x++) {
                A(B[x], x)
            }
        }
    };
    c.indexOf = function(z, y) {
        if (Array.indexOf) {
            return z.indexOf(y)
        }
        for (var x = 0,
        w = z.length; x < w; x++) {
            if (z[x] === y) {
                return x
            }
        }
        return - 1
    };
    c.map = function(y, x) {
        var w = [];
        c.each(y,
        function(A, z) {
            w.push(x(A, z))
        });
        return w
    };
    c.reduce = function(A, y, x) {
        var w = A.length;
        if (w == 0) {
            return x
        }
        var z = arguments.length == 3 ? x: A[--w];
        while (w--) {
            z = y(z, A[w])
        }
        return z
    };
    c.merge = function() {
        var A = {};
        for (var z = 0,
        w = arguments.length; z < w; z++) {
            var x = arguments[z];
            if (c.type(x) != "object") {
                continue
            }
            for (var y in x) {
                var C = x[y],
                B = A[y];
                A[y] = (B && c.type(C) == "object" && c.type(B) == "object") ? c.merge(B, C) : c.unlink(C)
            }
        }
        return A
    };
    c.unlink = function(y) {
        var x;
        switch (c.type(y)) {
        case "object":
            x = {};
            for (var A in y) {
                x[A] = c.unlink(y[A])
            }
            break;
        case "array":
            x = [];
            for (var z = 0,
            w = y.length; z < w; z++) {
                x[z] = c.unlink(y[z])
            }
            break;
        default:
            return y
        }
        return x
    };
    c.zip = function() {
        if (arguments.length === 0) {
            return []
        }
        for (var y = 0,
        x = [], w = arguments.length, B = arguments[0].length; y < B; y++) {
            for (var z = 0,
            A = []; z < w; z++) {
                A.push(arguments[z][y])
            }
            x.push(A)
        }
        return x
    };
    c.rgbToHex = function(A, z) {
        if (A.length < 3) {
            return null
        }
        if (A.length == 4 && A[3] == 0 && !z) {
            return "transparent"
        }
        var x = [];
        for (var w = 0; w < 3; w++) {
            var y = (A[w] - 0).toString(16);
            x.push(y.length == 1 ? "0" + y: y)
        }
        return z ? x: "#" + x.join("")
    };
    c.hexToRgb = function(y) {
        if (y.length != 7) {
            y = y.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
            y.shift();
            if (y.length != 3) {
                return null
            }
            var w = [];
            for (var x = 0; x < 3; x++) {
                var z = y[x];
                if (z.length == 1) {
                    z += z
                }
                w.push(parseInt(z, 16))
            }
            return w
        } else {
            y = parseInt(y.slice(1), 16);
            return [y >> 16, y >> 8 & 255, y & 255]
        }
    };
    c.destroy = function(w) {
        c.clean(w);
        if (w.parentNode) {
            w.parentNode.removeChild(w)
        }
        if (w.clearAttributes) {
            w.clearAttributes()
        }
    };
    c.clean = function(z) {
        for (var y = z.childNodes,
        x = 0,
        w = y.length; x < w; x++) {
            c.destroy(y[x])
        }
    };
    c.addEvent = function(y, x, w) {
        if (y.addEventListener) {
            y.addEventListener(x, w, false)
        } else {
            y.attachEvent("on" + x, w)
        }
    };
    c.addEvents = function(x, y) {
        for (var w in y) {
            c.addEvent(x, w, y[w])
        }
    };
    c.hasClass = function(x, w) {
        return (" " + x.className + " ").indexOf(" " + w + " ") > -1
    };
    c.addClass = function(x, w) {
        if (!c.hasClass(x, w)) {
            x.className = (x.className + " " + w)
        }
    };
    c.removeClass = function(x, w) {
        x.className = x.className.replace(new RegExp("(^|\\s)" + w + "(?:\\s|$)"), "$1")
    };
    c.getPos = function(y) {
        var B = A(y);
        var w = z(y);
        return {
            x: B.x - w.x,
            y: B.y - w.y
        };
        function A(D) {
            var C = {
                x: 0,
                y: 0
            };
            while (D && !x(D)) {
                C.x += D.offsetLeft;
                C.y += D.offsetTop;
                D = D.offsetParent
            }
            return C
        }
        function z(D) {
            var C = {
                x: 0,
                y: 0
            };
            while (D && !x(D)) {
                C.x += D.scrollLeft;
                C.y += D.scrollTop;
                D = D.parentNode
            }
            return C
        }
        function x(C) {
            return (/^(?:body|html)$/i).test(C.tagName)
        }
    };
    c.event = {
        get: function(x, w) {
            w = w || window;
            return x || w.event
        },
        getWheel: function(w) {
            return w.wheelDelta ? w.wheelDelta / 120 : -(w.detail || 0) / 3
        },
        isRightClick: function(w) {
            return (w.which == 3 || w.button == 2)
        },
        getPos: function(z, y) {
            y = y || window;
            z = z || y.event;
            var x = y.document;
            x = x.documentElement || x.body;
            if (z.touches && z.touches.length) {
                z = z.touches[0]
            }
            var w = {
                x: z.pageX || (z.clientX + x.scrollLeft),
                y: z.pageY || (z.clientY + x.scrollTop)
            };
            return w
        },
        stop: function(w) {
            if (w.stopPropagation) {
                w.stopPropagation()
            }
            w.cancelBubble = true;
            if (w.preventDefault) {
                w.preventDefault()
            } else {
                w.returnValue = false
            }
        }
    };
    $jit.util = $jit.id = c;
    var q = function(x) {
        x = x || {};
        var w = function() {
            for (var A in this) {
                if (typeof this[A] != "function") {
                    this[A] = c.unlink(this[A])
                }
            }
            this.constructor = w;
            if (q.prototyping) {
                return this
            }
            var z = this.initialize ? this.initialize.apply(this, arguments) : this;
            this.$$family = "class";
            return z
        };
        for (var y in q.Mutators) {
            if (!x[y]) {
                continue
            }
            x = q.Mutators[y](x, x[y]);
            delete x[y]
        }
        c.extend(w, this);
        w.constructor = q;
        w.prototype = x;
        return w
    };
    q.Mutators = {
        Implements: function(w, x) {
            c.each(c.splat(x),
            function(z) {
                q.prototyping = z;
                var y = (typeof z == "function") ? new z: z;
                for (var A in y) {
                    if (! (A in w)) {
                        w[A] = y[A]
                    }
                }
                delete q.prototyping
            });
            return w
        }
    };
    c.extend(q, {
        inherit: function(w, z) {
            for (var y in z) {
                var x = z[y];
                var B = w[y];
                var A = c.type(x);
                if (B && A == "function") {
                    if (x != B) {
                        q.override(w, y, x)
                    }
                } else {
                    if (A == "object") {
                        w[y] = c.merge(B, x)
                    } else {
                        w[y] = x
                    }
                }
            }
            return w
        },
        override: function(x, w, A) {
            var z = q.prototyping;
            if (z && x[w] != z[w]) {
                z = null
            }
            var y = function() {
                var B = this.parent;
                this.parent = z ? z[w] : x[w];
                var C = A.apply(this, arguments);
                this.parent = B;
                return C
            };
            x[w] = y
        }
    });
    q.prototype.implement = function() {
        var w = this.prototype;
        c.each(Array.prototype.slice.call(arguments || []),
        function(x) {
            q.inherit(w, x)
        });
        return this
    };
    $jit.Class = q;
    $jit.json = {
        prune: function(x, w) {
            this.each(x,
            function(z, y) {
                if (y == w && z.children) {
                    delete z.children;
                    z.children = []
                }
            })
        },
        getParent: function(w, A) {
            if (w.id == A) {
                return false
            }
            var z = w.children;
            if (z && z.length > 0) {
                for (var y = 0; y < z.length; y++) {
                    if (z[y].id == A) {
                        return w
                    } else {
                        var x = this.getParent(z[y], A);
                        if (x) {
                            return x
                        }
                    }
                }
            }
            return false
        },
        getSubtree: function(w, A) {
            if (w.id == A) {
                return w
            }
            for (var y = 0,
            z = w.children; y < z.length; y++) {
                var x = this.getSubtree(z[y], A);
                if (x != null) {
                    return x
                }
            }
            return null
        },
        eachLevel: function(w, B, y, A) {
            if (B <= y) {
                A(w, B);
                if (!w.children) {
                    return
                }
                for (var x = 0,
                z = w.children; x < z.length; x++) {
                    this.eachLevel(z[x], B + 1, y, A)
                }
            }
        },
        each: function(w, x) {
            this.eachLevel(w, 0, Number.MAX_VALUE, x)
        }
    };
    $jit.Trans = {
        $extend: true,
        linear: function(w) {
            return w
        }
    };
    var i = $jit.Trans; (function() {
        var w = function(z, y) {
            y = c.splat(y);
            return c.extend(z, {
                easeIn: function(A) {
                    return z(A, y)
                },
                easeOut: function(A) {
                    return 1 - z(1 - A, y)
                },
                easeInOut: function(A) {
                    return (A <= 0.5) ? z(2 * A, y) / 2 : (2 - z(2 * (1 - A), y)) / 2
                }
            })
        };
        var x = {
            Pow: function(z, y) {
                return Math.pow(z, y[0] || 6)
            },
            Expo: function(y) {
                return Math.pow(2, 8 * (y - 1))
            },
            Circ: function(y) {
                return 1 - Math.sin(Math.acos(y))
            },
            Sine: function(y) {
                return 1 - Math.sin((1 - y) * Math.PI / 2)
            },
            Back: function(z, y) {
                y = y[0] || 1.618;
                return Math.pow(z, 2) * ((y + 1) * z - y)
            },
            Bounce: function(B) {
                var A;
                for (var z = 0,
                y = 1; 1; z += y, y /= 2) {
                    if (B >= (7 - 4 * z) / 11) {
                        A = y * y - Math.pow((11 - 6 * z - 11 * B) / 4, 2);
                        break
                    }
                }
                return A
            },
            Elastic: function(z, y) {
                return Math.pow(2, 10 * --z) * Math.cos(20 * z * Math.PI * (y[0] || 1) / 3)
            }
        };
        c.each(x,
        function(z, y) {
            i[y] = w(z)
        });
        c.each(["Quad", "Cubic", "Quart", "Quint"],
        function(z, y) {
            i[z] = w(function(A) {
                return Math.pow(A, [y + 2])
            })
        })
    })();
    var u = new q({
        initialize: function(w) {
            this.setOptions(w)
        },
        setOptions: function(w) {
            var x = {
                duration: 2500,
                fps: 40,
                transition: i.Quart.easeInOut,
                compute: c.empty,
                complete: c.empty,
                link: "ignore"
            };
            this.opt = c.merge(x, w || {});
            return this
        },
        step: function() {
            var x = c.time(),
            w = this.opt;
            if (x < this.time + w.duration) {
                var y = w.transition((x - this.time) / w.duration);
                w.compute(y)
            } else {
                this.timer = clearInterval(this.timer);
                w.compute(1);
                w.complete()
            }
        },
        start: function() {
            if (!this.check()) {
                return this
            }
            this.time = 0;
            this.startTimer();
            return this
        },
        startTimer: function() {
            var w = this,
            x = this.opt.fps;
            if (this.timer) {
                return false
            }
            this.time = c.time() - this.time;
            this.timer = setInterval((function() {
                w.step()
            }), Math.round(1000 / x));
            return true
        },
        pause: function() {
            this.stopTimer();
            return this
        },
        resume: function() {
            this.startTimer();
            return this
        },
        stopTimer: function() {
            if (!this.timer) {
                return false
            }
            this.time = c.time() - this.time;
            this.timer = clearInterval(this.timer);
            return true
        },
        check: function() {
            if (!this.timer) {
                return true
            }
            if (this.opt.link == "cancel") {
                this.stopTimer();
                return true
            }
            return false
        }
    });
    var n = function() {
        var y = arguments;
        for (var A = 0,
        w = y.length,
        x = {}; A < w; A++) {
            var z = n[y[A]];
            if (z.$extend) {
                c.extend(x, z)
            } else {
                x[y[A]] = z
            }
        }
        return x
    };
    n.AreaChart = {
        $extend: true,
        animate: true,
        labelOffset: 3,
        type: "stacked",
        Tips: {
            enable: false,
            onShow: c.empty,
            onHide: c.empty
        },
        Events: {
            enable: false,
            onClick: c.empty
        },
        selectOnHover: true,
        showAggregates: true,
        showLabels: true,
        filterOnClick: false,
        restoreOnRightClick: false
    };
    n.Margin = {
        $extend: false,
        top: 0,
        left: 0,
        right: 0,
        bottom: 0
    };
    n.Canvas = {
        $extend: true,
        injectInto: "id",
        width: false,
        height: false,
        useCanvas: false,
        withLabels: true,
        background: false
    };
    n.Tree = {
        $extend: true,
        orientation: "left",
        subtreeOffset: 8,
        siblingOffset: 5,
        indent: 10,
        multitree: false,
        align: "center"
    };
    n.Node = {
        $extend: false,
        overridable: false,
        type: "circle",
        color: "#ccb",
        alpha: 1,
        dim: 3,
        height: 20,
        width: 90,
        autoHeight: false,
        autoWidth: false,
        lineWidth: 1,
        transform: true,
        align: "center",
        angularWidth: 1,
        span: 1,
        CanvasStyles: {}
    };
    n.Edge = {
        $extend: false,
        overridable: false,
        type: "line",
        color: "#ccb",
        lineWidth: 1,
        dim: 15,
        alpha: 1,
        epsilon: 7,
        CanvasStyles: {}
    };
    n.Fx = {
        $extend: true,
        fps: 40,
        duration: 2500,
        transition: $jit.Trans.Quart.easeInOut,
        clearCanvas: true
    };
    n.Label = {
        $extend: false,
        overridable: false,
        type: "HTML",
        style: " ",
        size: 10,
        family: "sans-serif",
        textAlign: "center",
        textBaseline: "alphabetic",
        color: "#fff"
    };
    n.Tips = {
        $extend: false,
        enable: false,
        type: "auto",
        offsetX: 20,
        offsetY: 20,
        force: false,
        onShow: c.empty,
        onHide: c.empty
    };
    n.NodeStyles = {
        $extend: false,
        enable: false,
        type: "auto",
        stylesHover: false,
        stylesClick: false
    };
    n.Events = {
        $extend: false,
        enable: false,
        enableForEdges: false,
        type: "auto",
        onClick: c.empty,
        onRightClick: c.empty,
        onMouseMove: c.empty,
        onMouseEnter: c.empty,
        onMouseLeave: c.empty,
        onDragStart: c.empty,
        onDragMove: c.empty,
        onDragCancel: c.empty,
        onDragEnd: c.empty,
        onTouchStart: c.empty,
        onTouchMove: c.empty,
        onTouchEnd: c.empty,
        onMouseWheel: c.empty
    };
    n.Navigation = {
        $extend: false,
        enable: false,
        type: "auto",
        panning: false,
        zooming: false
    };
    n.Controller = {
        $extend: true,
        onBeforeCompute: c.empty,
        onAfterCompute: c.empty,
        onCreateLabel: c.empty,
        onPlaceLabel: c.empty,
        onComplete: c.empty,
        onBeforePlotLine: c.empty,
        onAfterPlotLine: c.empty,
        onBeforePlotNode: c.empty,
        onAfterPlotNode: c.empty,
        request: false
    };
    var t = {
        initialize: function(y, w) {
            this.viz = w;
            this.canvas = w.canvas;
            this.config = w.config[y];
            this.nodeTypes = w.fx.nodeTypes;
            var x = this.config.type;
            this.dom = x == "auto" ? (w.config.Label.type != "Native") : (x != "Native");
            this.labelContainer = this.dom && w.labels.getLabelContainer();
            this.isEnabled() && this.initializePost()
        },
        initializePost: c.empty,
        setAsProperty: c.lambda(false),
        isEnabled: function() {
            return this.config.enable
        },
        isLabel: function(z, y) {
            z = c.event.get(z, y);
            var w = this.labelContainer,
            x = z.target || z.srcElement;
            if (x && x.parentNode == w) {
                return x
            }
            return false
        }
    };
    var h = {
        onMouseUp: c.empty,
        onMouseDown: c.empty,
        onMouseMove: c.empty,
        onMouseOver: c.empty,
        onMouseOut: c.empty,
        onMouseWheel: c.empty,
        onTouchStart: c.empty,
        onTouchMove: c.empty,
        onTouchEnd: c.empty,
        onTouchCancel: c.empty
    };
    var s = new q({
        initialize: function(w) {
            this.viz = w;
            this.canvas = w.canvas;
            this.node = false;
            this.edge = false;
            this.registeredObjects = [];
            this.attachEvents()
        },
        attachEvents: function() {
            var y = this.canvas.getElement(),
            x = this;
            y.oncontextmenu = c.lambda(false);
            c.addEvents(y, {
                mouseup: function(B, A) {
                    var z = c.event.get(B, A);
                    x.handleEvent("MouseUp", B, A, x.makeEventObject(B, A), c.event.isRightClick(z))
                },
                mousedown: function(B, A) {
                    var z = c.event.get(B, A);
                    x.handleEvent("MouseDown", B, A, x.makeEventObject(B, A), c.event.isRightClick(z))
                },
                mousemove: function(A, z) {
                    x.handleEvent("MouseMove", A, z, x.makeEventObject(A, z))
                },
                mouseover: function(A, z) {
                    x.handleEvent("MouseOver", A, z, x.makeEventObject(A, z))
                },
                mouseout: function(A, z) {
                    x.handleEvent("MouseOut", A, z, x.makeEventObject(A, z))
                },
                touchstart: function(A, z) {
                    x.handleEvent("TouchStart", A, z, x.makeEventObject(A, z))
                },
                touchmove: function(A, z) {
                    x.handleEvent("TouchMove", A, z, x.makeEventObject(A, z))
                },
                touchend: function(A, z) {
                    x.handleEvent("TouchEnd", A, z, x.makeEventObject(A, z))
                }
            });
            var w = function(C, B) {
                var A = c.event.get(C, B);
                var z = c.event.getWheel(A);
                x.handleEvent("MouseWheel", C, B, z)
            };
            if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {
                c.addEvent(y, "mousewheel", w)
            } else {
                y.addEventListener("DOMMouseScroll", w, false)
            }
        },
        register: function(w) {
            this.registeredObjects.push(w)
        },
        handleEvent: function() {
            var x = Array.prototype.slice.call(arguments),
            A = x.shift();
            for (var z = 0,
            y = this.registeredObjects,
            w = y.length; z < w; z++) {
                y[z]["on" + A].apply(y[z], x)
            }
        },
        makeEventObject: function(C, B) {
            var z = this,
            A = this.viz.graph,
            y = this.viz.fx,
            x = y.nodeTypes,
            w = y.edgeTypes;
            return {
                pos: false,
                node: false,
                edge: false,
                contains: false,
                getNodeCalled: false,
                getEdgeCalled: false,
                getPos: function() {
                    var F = z.viz.canvas,
                    G = F.getSize(),
                    H = F.getPos(),
                    E = F.translateOffsetX,
                    D = F.translateOffsetY,
                    K = F.scaleOffsetX,
                    I = F.scaleOffsetY,
                    J = c.event.getPos(C, B);
                    this.pos = {
                        x: (J.x - H.x - G.width / 2 - E) * 1 / K,
                        y: (J.y - H.y - G.height / 2 - D) * 1 / I
                    };
                    return this.pos
                },
                getNode: function() {
                    if (this.getNodeCalled) {
                        return this.node
                    }
                    this.getNodeCalled = true;
                    for (var G in A.nodes) {
                        var F = A.nodes[G],
                        E = F && x[F.getData("type")],
                        D = E && E.contains && E.contains.call(y, F, this.getPos());
                        if (D) {
                            this.contains = D;
                            return z.node = this.node = F
                        }
                    }
                    return z.node = this.node = false
                },
                getEdge: function() {
                    if (this.getEdgeCalled) {
                        return this.edge
                    }
                    this.getEdgeCalled = true;
                    var F = {};
                    for (var J in A.edges) {
                        var H = A.edges[J];
                        F[J] = true;
                        for (var I in H) {
                            if (I in F) {
                                continue
                            }
                            var G = H[I],
                            E = G && w[G.getData("type")],
                            D = E && E.contains && E.contains.call(y, G, this.getPos());
                            if (D) {
                                this.contains = D;
                                return z.edge = this.edge = G
                            }
                        }
                    }
                    return z.edge = this.edge = false
                },
                getContains: function() {
                    if (this.getNodeCalled) {
                        return this.contains
                    }
                    this.getNode();
                    return this.contains
                }
            }
        }
    });
    var o = {
        initializeExtras: function() {
            var x = new s(this),
            w = this;
            c.each(["NodeStyles", "Tips", "Navigation", "Events"],
            function(y) {
                var z = new o.Classes[y](y, w);
                if (z.isEnabled()) {
                    x.register(z)
                }
                if (z.setAsProperty()) {
                    w[y.toLowerCase()] = z
                }
            })
        }
    };
    o.Classes = {};
    o.Classes.Events = new q({
        Implements: [t, h],
        initializePost: function() {
            this.fx = this.viz.fx;
            this.ntypes = this.viz.fx.nodeTypes;
            this.etypes = this.viz.fx.edgeTypes;
            this.hovered = false;
            this.pressed = false;
            this.touched = false;
            this.touchMoved = false;
            this.moved = false
        },
        setAsProperty: c.lambda(true),
        onMouseUp: function(A, z, x, y) {
            var w = c.event.get(A, z);
            if (!this.moved) {
                if (y) {
                    this.config.onRightClick(this.hovered, x, w)
                } else {
                    this.config.onClick(this.pressed, x, w)
                }
            }
            if (this.pressed) {
                if (this.moved) {
                    this.config.onDragEnd(this.pressed, x, w)
                } else {
                    this.config.onDragCancel(this.pressed, x, w)
                }
                this.pressed = this.moved = false
            }
        },
        onMouseOut: function(B, A, z) {
            var x = c.event.get(B, A),
            y;
            if (this.dom && (y = this.isLabel(B, A))) {
                this.config.onMouseLeave(this.viz.graph.getNode(y.id), z, x);
                this.hovered = false;
                return
            }
            var w = x.relatedTarget,
            C = this.canvas.getElement();
            while (w && w.parentNode) {
                if (C == w.parentNode) {
                    return
                }
                w = w.parentNode
            }
            if (this.hovered) {
                this.config.onMouseLeave(this.hovered, z, x);
                this.hovered = false
            }
        },
        onMouseOver: function(A, z, y) {
            var w = c.event.get(A, z),
            x;
            if (this.dom && (x = this.isLabel(A, z))) {
                this.hovered = this.viz.graph.getNode(x.id);
                this.config.onMouseEnter(this.hovered, y, w)
            }
        },
        onMouseMove: function(C, B, A) {
            var x, w = c.event.get(C, B);
            if (this.pressed) {
                this.moved = true;
                this.config.onDragMove(this.pressed, A, w);
                return
            }
            if (this.dom) {
                this.config.onMouseMove(this.hovered, A, w)
            } else {
                if (this.hovered) {
                    var D = this.hovered;
                    var z = D.nodeFrom ? this.etypes[D.getData("type")] : this.ntypes[D.getData("type")];
                    var y = z && z.contains && z.contains.call(this.fx, D, A.getPos());
                    if (y) {
                        this.config.onMouseMove(D, A, w);
                        return
                    } else {
                        this.config.onMouseLeave(D, A, w);
                        this.hovered = false
                    }
                }
                if (this.hovered = (A.getNode() || (this.config.enableForEdges && A.getEdge()))) {
                    this.config.onMouseEnter(this.hovered, A, w)
                } else {
                    this.config.onMouseMove(false, A, w)
                }
            }
        },
        onMouseWheel: function(x, w, y) {
            this.config.onMouseWheel(y, c.event.get(x, w))
        },
        onMouseDown: function(z, y, x) {
            var w = c.event.get(z, y);
            this.pressed = x.getNode() || (this.config.enableForEdges && x.getEdge());
            this.config.onDragStart(this.pressed, x, w)
        },
        onTouchStart: function(z, y, x) {
            var w = c.event.get(z, y);
            this.touched = x.getNode() || (this.config.enableForEdges && x.getEdge());
            this.config.onTouchStart(this.touched, x, w)
        },
        onTouchMove: function(z, y, x) {
            var w = c.event.get(z, y);
            if (this.touched) {
                this.touchMoved = true;
                this.config.onTouchMove(this.touched, x, w)
            }
        },
        onTouchEnd: function(z, y, x) {
            var w = c.event.get(z, y);
            if (this.touched) {
                if (this.touchMoved) {
                    this.config.onTouchEnd(this.touched, x, w)
                } else {
                    this.config.onTouchCancel(this.touched, x, w)
                }
                this.touched = this.touchMoved = false
            }
        }
    });
    o.Classes.Tips = new q({
        Implements: [t, h],
        initializePost: function() {
            if (document.body) {
                var w = c("_tooltip") || document.createElement("div");
                w.id = "_tooltip";
                w.className = "tip";
                c.extend(w.style, {
                    position: "absolute",
                    display: "none",
                    zIndex: 13000
                });
                document.body.appendChild(w);
                this.tip = w;
                this.node = false
            }
        },
        setAsProperty: c.lambda(true),
        onMouseOut: function(y, x) {
            if (this.dom && this.isLabel(y, x)) {
                this.hide(true);
                return
            }
            var w = y.relatedTarget,
            z = this.canvas.getElement();
            while (w && w.parentNode) {
                if (z == w.parentNode) {
                    return
                }
                w = w.parentNode
            }
            this.hide(false)
        },
        onMouseOver: function(y, x) {
            var w;
            if (this.dom && (w = this.isLabel(y, x))) {
                this.node = this.viz.graph.getNode(w.id);
                this.config.onShow(this.tip, this.node, w)
            }
        },
        onMouseMove: function(z, y, w) {
            if (this.dom && this.isLabel(z, y)) {
                this.setTooltipPosition(c.event.getPos(z, y))
            }
            if (!this.dom) {
                var x = w.getNode();
                if (!x) {
                    this.hide(true);
                    return
                }
                if (this.config.force || !this.node || this.node.id != x.id) {
                    this.node = x;
                    this.config.onShow(this.tip, x, w.getContains())
                }
                this.setTooltipPosition(c.event.getPos(z, y))
            }
        },
        setTooltipPosition: function(F) {
            var B = this.tip,
            A = B.style,
            z = this.config;
            A.display = "";
            var D = {
                height: document.body.clientHeight,
                width: document.body.clientWidth
            };
            var C = {
                width: B.offsetWidth,
                height: B.offsetHeight
            };
            var w = z.offsetX,
            E = z.offsetY;
            A.top = ((F.y + E + C.height > D.height) ? (F.y - C.height - E) : F.y + E) + "px";
            A.left = ((F.x + C.width + w > D.width) ? (F.x - C.width - w) : F.x + w) + "px"
        },
        hide: function(w) {
            this.tip.style.display = "none";
            w && this.config.onHide()
        }
    });
    o.Classes.NodeStyles = new q({
        Implements: [t, h],
        initializePost: function() {
            this.fx = this.viz.fx;
            this.types = this.viz.fx.nodeTypes;
            this.nStyles = this.config;
            this.nodeStylesOnHover = this.nStyles.stylesHover;
            this.nodeStylesOnClick = this.nStyles.stylesClick;
            this.hoveredNode = false;
            this.fx.nodeFxAnimation = new u();
            this.down = false;
            this.move = false
        },
        onMouseOut: function(y, x) {
            this.down = this.move = false;
            if (!this.hoveredNode) {
                return
            }
            if (this.dom && this.isLabel(y, x)) {
                this.toggleStylesOnHover(this.hoveredNode, false)
            }
            var w = y.relatedTarget,
            z = this.canvas.getElement();
            while (w && w.parentNode) {
                if (z == w.parentNode) {
                    return
                }
                w = w.parentNode
            }
            this.toggleStylesOnHover(this.hoveredNode, false);
            this.hoveredNode = false
        },
        onMouseOver: function(z, y) {
            var w;
            if (this.dom && (w = this.isLabel(z, y))) {
                var x = this.viz.graph.getNode(w.id);
                if (x.selected) {
                    return
                }
                this.hoveredNode = x;
                this.toggleStylesOnHover(this.hoveredNode, true)
            }
        },
        onMouseDown: function(A, z, x, y) {
            if (y) {
                return
            }
            var w;
            if (this.dom && (w = this.isLabel(A, z))) {
                this.down = this.viz.graph.getNode(w.id)
            } else {
                if (!this.dom) {
                    this.down = x.getNode()
                }
            }
            this.move = false
        },
        onMouseUp: function(z, y, w, x) {
            if (x) {
                return
            }
            if (!this.move) {
                this.onClick(w.getNode())
            }
            this.down = this.move = false
        },
        getRestoredStyles: function(x, w) {
            var z = {},
            y = this["nodeStylesOn" + w];
            for (var A in y) {
                z[A] = x.styles["$" + A]
            }
            return z
        },
        toggleStylesOnHover: function(w, x) {
            if (this.nodeStylesOnHover) {
                this.toggleStylesOn("Hover", w, x)
            }
        },
        toggleStylesOnClick: function(w, x) {
            if (this.nodeStylesOnClick) {
                this.toggleStylesOn("Click", w, x)
            }
        },
        toggleStylesOn: function(A, w, C) {
            var D = this.viz;
            var B = this.nStyles;
            if (C) {
                var z = this;
                if (!w.styles) {
                    w.styles = c.merge(w.data, {})
                }
                for (var E in this["nodeStylesOn" + A]) {
                    var x = "$" + E;
                    if (! (x in w.styles)) {
                        w.styles[x] = w.getData(E)
                    }
                }
                D.fx.nodeFx(c.extend({
                    elements: {
                        id: w.id,
                        properties: z["nodeStylesOn" + A]
                    },
                    transition: i.Quart.easeOut,
                    duration: 300,
                    fps: 40
                },
                this.config))
            } else {
                var y = this.getRestoredStyles(w, A);
                D.fx.nodeFx(c.extend({
                    elements: {
                        id: w.id,
                        properties: y
                    },
                    transition: i.Quart.easeOut,
                    duration: 300,
                    fps: 40
                },
                this.config))
            }
        },
        onClick: function(w) {
            if (!w) {
                return
            }
            var x = this.nodeStylesOnClick;
            if (!x) {
                return
            }
            if (w.selected) {
                this.toggleStylesOnClick(w, false);
                delete w.selected
            } else {
                this.viz.graph.eachNode(function(z) {
                    if (z.selected) {
                        for (var y in x) {
                            z.setData(y, z.styles["$" + y], "end")
                        }
                        delete z.selected
                    }
                });
                this.toggleStylesOnClick(w, true);
                w.selected = true;
                delete w.hovered;
                this.hoveredNode = false
            }
        },
        onMouseMove: function(C, B, z) {
            if (this.down) {
                this.move = true
            }
            if (this.dom && this.isLabel(C, B)) {
                return
            }
            var A = this.nodeStylesOnHover;
            if (!A) {
                return
            }
            if (!this.dom) {
                if (this.hoveredNode) {
                    var x = this.types[this.hoveredNode.getData("type")];
                    var w = x && x.contains && x.contains.call(this.fx, this.hoveredNode, z.getPos());
                    if (w) {
                        return
                    }
                }
                var y = z.getNode();
                if (!this.hoveredNode && !y) {
                    return
                }
                if (y.hovered) {
                    return
                }
                if (y && !y.selected) {
                    this.fx.nodeFxAnimation.stopTimer();
                    this.viz.graph.eachNode(function(E) {
                        if (E.hovered && !E.selected) {
                            for (var D in A) {
                                E.setData(D, E.styles["$" + D], "end")
                            }
                            delete E.hovered
                        }
                    });
                    y.hovered = true;
                    this.hoveredNode = y;
                    this.toggleStylesOnHover(y, true)
                } else {
                    if (this.hoveredNode && !this.hoveredNode.selected) {
                        this.fx.nodeFxAnimation.stopTimer();
                        this.toggleStylesOnHover(this.hoveredNode, false);
                        delete this.hoveredNode.hovered;
                        this.hoveredNode = false
                    }
                }
            }
        }
    });
    o.Classes.Navigation = new q({
        Implements: [t, h],
        initializePost: function() {
            this.pos = false;
            this.pressed = false
        },
        onMouseWheel: function(z, y, w) {
            if (!this.config.zooming) {
                return
            }
            c.event.stop(c.event.get(z, y));
            var A = this.config.zooming / 1000,
            x = 1 + w * A;
            this.canvas.scale(x, x)
        },
        onMouseDown: function(B, A, z) {
            if (!this.config.panning) {
                return
            }
            if (this.config.panning == "avoid nodes" && z.getNode()) {
                return
            }
            this.pressed = true;
            this.pos = z.getPos();
            var y = this.canvas,
            x = y.translateOffsetX,
            w = y.translateOffsetY,
            D = y.scaleOffsetX,
            C = y.scaleOffsetY;
            this.pos.x *= D;
            this.pos.x += x;
            this.pos.y *= C;
            this.pos.y += w
        },
        onMouseMove: function(D, C, F) {
            if (!this.config.panning) {
                return
            }
            if (!this.pressed) {
                return
            }
            if (this.config.panning == "avoid nodes" && F.getNode()) {
                return
            }
            var B = this.pos,
            E = F.getPos(),
            z = this.canvas,
            A = z.translateOffsetX,
            w = z.translateOffsetY,
            J = z.scaleOffsetX,
            H = z.scaleOffsetY;
            E.x *= J;
            E.y *= H;
            E.x += A;
            E.y += w;
            var I = E.x - B.x,
            G = E.y - B.y;
            this.pos = E;
            this.canvas.translate(I * 1 / J, G * 1 / H)
        },
        onMouseUp: function(z, y, x, w) {
            if (!this.config.panning) {
                return
            }
            this.pressed = false
        }
    });
    var l; (function() {
        var w = typeof HTMLCanvasElement,
        y = (w == "object" || w == "function");
        function x(z, A) {
            var B = document.createElement(z);
            for (var C in A) {
                if (typeof A[C] == "object") {
                    c.extend(B[C], A[C])
                } else {
                    B[C] = A[C]
                }
            }
            if (z == "canvas" && !y && G_vmlCanvasManager) {
                B = G_vmlCanvasManager.initElement(document.body.appendChild(B))
            }
            return B
        }
        $jit.Canvas = l = new q({
            canvases: [],
            pos: false,
            element: false,
            labelContainer: false,
            translateOffsetX: 0,
            translateOffsetY: 0,
            scaleOffsetX: 1,
            scaleOffsetY: 1,
            initialize: function(K, E) {
                this.viz = K;
                this.opt = E;
                var B = c.type(E.injectInto) == "string" ? E.injectInto: E.injectInto.id,
                C = B + "-label",
                z = c(B),
                D = E.width || z.offsetWidth,
                L = E.height || z.offsetHeight;
                this.id = B;
                var F = {
                    injectInto: B,
                    width: D,
                    height: L
                };
                this.element = x("div", {
                    id: B + "-canvaswidget",
                    style: {
                        position: "relative",
                        width: D + "px",
                        height: L + "px"
                    }
                });
                this.labelContainer = this.createLabelContainer(E.Label.type, C, F);
                this.canvases.push(new l.Base({
                    config: c.extend({
                        idSuffix: "-canvas"
                    },
                    F),
                    plot: function(M) {
                        K.fx.plot()
                    },
                    resize: function() {
                        K.refresh()
                    }
                }));
                var G = E.background;
                if (G) {
                    var J = new l.Background[G.type](K, c.extend(G, F));
                    this.canvases.push(new l.Base(J))
                }
                var I = this.canvases.length;
                while (I--) {
                    this.element.appendChild(this.canvases[I].canvas);
                    if (I > 0) {
                        this.canvases[I].plot()
                    }
                }
                this.element.appendChild(this.labelContainer);
                z.appendChild(this.element);
                var A = null,
                H = this;
                c.addEvent(window, "scroll",
                function() {
                    clearTimeout(A);
                    A = setTimeout(function() {
                        H.getPos(true)
                    },
                    500)
                })
            },
            getCtx: function(z) {
                return this.canvases[z || 0].getCtx()
            },
            getConfig: function() {
                return this.opt
            },
            getElement: function() {
                return this.element
            },
            getSize: function(z) {
                return this.canvases[z || 0].getSize()
            },
            resize: function(D, z) {
                this.getPos(true);
                this.translateOffsetX = this.translateOffsetY = 0;
                this.scaleOffsetX = this.scaleOffsetY = 1;
                for (var B = 0,
                A = this.canvases.length; B < A; B++) {
                    this.canvases[B].resize(D, z)
                }
                var C = this.element.style;
                C.width = D + "px";
                C.height = z + "px";
                if (this.labelContainer) {
                    this.labelContainer.style.width = D + "px"
                }
            },
            translate: function(z, D, C) {
                this.translateOffsetX += z * this.scaleOffsetX;
                this.translateOffsetY += D * this.scaleOffsetY;
                for (var B = 0,
                A = this.canvases.length; B < A; B++) {
                    this.canvases[B].translate(z, D, C)
                }
            },
            scale: function(E, B, C) {
                var F = this.scaleOffsetX * E,
                D = this.scaleOffsetY * B;
                var H = this.translateOffsetX * (E - 1) / F,
                G = this.translateOffsetY * (B - 1) / D;
                this.scaleOffsetX = F;
                this.scaleOffsetY = D;
                for (var A = 0,
                z = this.canvases.length; A < z; A++) {
                    this.canvases[A].scale(E, B, true)
                }
                this.translate(H, G, false)
            },
            getPos: function(z) {
                if (z || !this.pos) {
                    return this.pos = c.getPos(this.getElement())
                }
                return this.pos
            },
            clear: function(z) {
                this.canvases[z || 0].clear()
            },
            path: function(A, B) {
                var z = this.canvases[0].getCtx();
                z.beginPath();
                B(z);
                z[A]();
                z.closePath()
            },
            createLabelContainer: function(B, F, E) {
                var D = "http://www.w3.org/2000/svg";
                if (B == "HTML" || B == "Native") {
                    return x("div", {
                        id: F,
                        style: {
                            overflow: "visible",
                            position: "absolute",
                            top: 0,
                            left: 0,
                            width: E.width + "px",
                            height: 0
                        }
                    })
                } else {
                    if (B == "SVG") {
                        var C = document.createElementNS(D, "svg:svg");
                        C.setAttribute("width", E.width);
                        C.setAttribute("height", E.height);
                        var A = C.style;
                        A.position = "absolute";
                        A.left = A.top = "0px";
                        var z = document.createElementNS(D, "svg:g");
                        z.setAttribute("width", E.width);
                        z.setAttribute("height", E.height);
                        z.setAttribute("x", 0);
                        z.setAttribute("y", 0);
                        z.setAttribute("id", F);
                        C.appendChild(z);
                        return C
                    }
                }
            }
        });
        l.Base = new q({
            translateOffsetX: 0,
            translateOffsetY: 0,
            scaleOffsetX: 1,
            scaleOffsetY: 1,
            initialize: function(z) {
                this.viz = z;
                this.opt = z.config;
                this.size = false;
                this.createCanvas();
                this.translateToCenter()
            },
            createCanvas: function() {
                var A = this.opt,
                B = A.width,
                z = A.height;
                this.canvas = x("canvas", {
                    id: A.injectInto + A.idSuffix,
                    width: B,
                    height: z,
                    style: {
                        position: "absolute",
                        top: 0,
                        left: 0,
                        width: B + "px",
                        height: z + "px"
                    }
                })
            },
            getCtx: function() {
                if (!this.ctx) {
                    return this.ctx = this.canvas.getContext("2d")
                }
                return this.ctx
            },
            getSize: function() {
                if (this.size) {
                    return this.size
                }
                var z = this.canvas;
                return this.size = {
                    width: z.width,
                    height: z.height
                }
            },
            translateToCenter: function(C) {
                var A = this.getSize(),
                B = C ? (A.width - C.width - this.translateOffsetX * 2) : A.width;
                height = C ? (A.height - C.height - this.translateOffsetY * 2) : A.height;
                var z = this.getCtx();
                C && z.scale(1 / this.scaleOffsetX, 1 / this.scaleOffsetY);
                z.translate(B / 2, height / 2)
            },
            resize: function(C, z) {
                var B = this.getSize(),
                A = this.canvas,
                D = A.style;
                this.size = false;
                A.width = C;
                A.height = z;
                D.width = C + "px";
                D.height = z + "px";
                if (!y) {
                    this.translateToCenter(B)
                } else {
                    this.translateToCenter()
                }
                this.translateOffsetX = this.translateOffsetY = 0;
                this.scaleOffsetX = this.scaleOffsetY = 1;
                this.clear();
                this.viz.resize(C, z, this)
            },
            translate: function(z, D, A) {
                var C = this.scaleOffsetX,
                B = this.scaleOffsetY;
                this.translateOffsetX += z * C;
                this.translateOffsetY += D * B;
                this.getCtx().translate(z, D); ! A && this.plot()
            },
            scale: function(z, B, A) {
                this.scaleOffsetX *= z;
                this.scaleOffsetY *= B;
                this.getCtx().scale(z, B); ! A && this.plot()
            },
            clear: function() {
                var B = this.getSize(),
                A = this.translateOffsetX,
                z = this.translateOffsetY,
                D = this.scaleOffsetX,
                C = this.scaleOffsetY;
                this.getCtx().clearRect(( - B.width / 2 - A) * 1 / D, ( - B.height / 2 - z) * 1 / C, B.width * 1 / D, B.height * 1 / C)
            },
            plot: function() {
                this.clear();
                this.viz.plot(this)
            }
        });
        l.Background = {};
        l.Background.Circles = new q({
            initialize: function(z, A) {
                this.viz = z;
                this.config = c.merge({
                    idSuffix: "-bkcanvas",
                    levelDistance: 100,
                    numberOfCircles: 6,
                    CanvasStyles: {},
                    offset: 0
                },
                A)
            },
            resize: function(A, z, B) {
                this.plot(B)
            },
            plot: function(z) {
                var A = z.canvas,
                G = z.getCtx(),
                D = this.config,
                F = D.CanvasStyles;
                for (var H in F) {
                    G[H] = F[H]
                }
                var B = D.numberOfCircles,
                E = D.levelDistance;
                for (var C = 1; C <= B; C++) {
                    G.beginPath();
                    G.arc(0, 0, E * C, 0, 2 * Math.PI, false);
                    G.stroke();
                    G.closePath()
                }
            }
        })
    })();
    var b = function(x, w) {
        this.theta = x;
        this.rho = w
    };
    $jit.Polar = b;
    b.prototype = {
        getc: function(w) {
            return this.toComplex(w)
        },
        getp: function() {
            return this
        },
        set: function(w) {
            w = w.getp();
            this.theta = w.theta;
            this.rho = w.rho
        },
        setc: function(w, z) {
            this.rho = Math.sqrt(w * w + z * z);
            this.theta = Math.atan2(z, w);
            if (this.theta < 0) {
                this.theta += Math.PI * 2
            }
        },
        setp: function(x, w) {
            this.theta = x;
            this.rho = w
        },
        clone: function() {
            return new b(this.theta, this.rho)
        },
        toComplex: function(A) {
            var w = Math.cos(this.theta) * this.rho;
            var z = Math.sin(this.theta) * this.rho;
            if (A) {
                return {
                    x: w,
                    y: z
                }
            }
            return new p(w, z)
        },
        add: function(w) {
            return new b(this.theta + w.theta, this.rho + w.rho)
        },
        scale: function(w) {
            return new b(this.theta, this.rho * w)
        },
        equals: function(w) {
            return this.theta == w.theta && this.rho == w.rho
        },
        $add: function(w) {
            this.theta = this.theta + w.theta;
            this.rho += w.rho;
            return this
        },
        $madd: function(w) {
            this.theta = (this.theta + w.theta) % (Math.PI * 2);
            this.rho += w.rho;
            return this
        },
        $scale: function(w) {
            this.rho *= w;
            return this
        },
        interpolate: function(y, F) {
            var z = Math.PI,
            C = z * 2;
            var x = function(H) {
                var G = (H < 0) ? (H % C) + C: H % C;
                return G
            };
            var B = this.theta,
            E = y.theta;
            var A, D = Math.abs(B - E);
            if (D == z) {
                if (B > E) {
                    A = x((E + ((B - C) - E) * F))
                } else {
                    A = x((E - C + (B - (E)) * F))
                }
            } else {
                if (D >= z) {
                    if (B > E) {
                        A = x((E + ((B - C) - E) * F))
                    } else {
                        A = x((E - C + (B - (E - C)) * F))
                    }
                } else {
                    A = x((E + (B - E) * F))
                }
            }
            var w = (this.rho - y.rho) * F + y.rho;
            return {
                theta: A,
                rho: w
            }
        }
    };
    var k = function(x, w) {
        return new b(x, w)
    };
    b.KER = k(0, 0);
    var p = function(w, z) {
        this.x = w;
        this.y = z
    };
    $jit.Complex = p;
    p.prototype = {
        getc: function() {
            return this
        },
        getp: function(w) {
            return this.toPolar(w)
        },
        set: function(w) {
            w = w.getc(true);
            this.x = w.x;
            this.y = w.y
        },
        setc: function(w, z) {
            this.x = w;
            this.y = z
        },
        setp: function(x, w) {
            this.x = Math.cos(x) * w;
            this.y = Math.sin(x) * w
        },
        clone: function() {
            return new p(this.x, this.y)
        },
        toPolar: function(y) {
            var w = this.norm();
            var x = Math.atan2(this.y, this.x);
            if (x < 0) {
                x += Math.PI * 2
            }
            if (y) {
                return {
                    theta: x,
                    rho: w
                }
            }
            return new b(x, w)
        },
        norm: function() {
            return Math.sqrt(this.squaredNorm())
        },
        squaredNorm: function() {
            return this.x * this.x + this.y * this.y
        },
        add: function(w) {
            return new p(this.x + w.x, this.y + w.y)
        },
        prod: function(w) {
            return new p(this.x * w.x - this.y * w.y, this.y * w.x + this.x * w.y)
        },
        conjugate: function() {
            return new p(this.x, -this.y)
        },
        scale: function(w) {
            return new p(this.x * w, this.y * w)
        },
        equals: function(w) {
            return this.x == w.x && this.y == w.y
        },
        $add: function(w) {
            this.x += w.x;
            this.y += w.y;
            return this
        },
        $prod: function(A) {
            var w = this.x,
            z = this.y;
            this.x = w * A.x - z * A.y;
            this.y = z * A.x + w * A.y;
            return this
        },
        $conjugate: function() {
            this.y = -this.y;
            return this
        },
        $scale: function(w) {
            this.x *= w;
            this.y *= w;
            return this
        },
        $div: function(B) {
            var w = this.x,
            A = this.y;
            var z = B.squaredNorm();
            this.x = w * B.x + A * B.y;
            this.y = A * B.x - w * B.y;
            return this.$scale(1 / z)
        }
    };
    var r = function(x, w) {
        return new p(x, w)
    };
    p.KER = r(0, 0);
    $jit.Graph = new q({
        initialize: function(y, x, w, C) {
            var A = {
                complex: false,
                Node: {}
            };
            this.Node = x;
            this.Edge = w;
            this.Label = C;
            this.opt = c.merge(A, y || {});
            this.nodes = {};
            this.edges = {};
            var z = this;
            this.nodeList = {};
            for (var B in j) {
                z.nodeList[B] = (function(D) {
                    return function() {
                        var E = Array.prototype.slice.call(arguments);
                        z.eachNode(function(F) {
                            F[D].apply(F, E)
                        })
                    }
                })(B)
            }
        },
        getNode: function(w) {
            if (this.hasNode(w)) {
                return this.nodes[w]
            }
            return false
        },
        getByName: function(w) {
            for (var y in this.nodes) {
                var x = this.nodes[y];
                if (x.name == w) {
                    return x
                }
            }
            return false
        },
        getAdjacence: function(x, w) {
            if (x in this.edges) {
                return this.edges[x][w]
            }
            return false
        },
        addNode: function(x) {
            if (!this.nodes[x.id]) {
                var w = this.edges[x.id] = {};
                this.nodes[x.id] = new e.Node(c.extend({
                    id: x.id,
                    name: x.name,
                    data: c.merge(x.data || {},
                    {}),
                    adjacencies: w
                },
                this.opt.Node), this.opt.complex, this.Node, this.Edge, this.Label)
            }
            return this.nodes[x.id]
        },
        addAdjacence: function(z, y, x) {
            if (!this.hasNode(z.id)) {
                this.addNode(z)
            }
            if (!this.hasNode(y.id)) {
                this.addNode(y)
            }
            z = this.nodes[z.id];
            y = this.nodes[y.id];
            if (!z.adjacentTo(y)) {
                var A = this.edges[z.id] = this.edges[z.id] || {};
                var w = this.edges[y.id] = this.edges[y.id] || {};
                A[y.id] = w[z.id] = new e.Adjacence(z, y, x, this.Edge, this.Label);
                return A[y.id]
            }
            return this.edges[z.id][y.id]
        },
        removeNode: function(y) {
            if (this.hasNode(y)) {
                delete this.nodes[y];
                var x = this.edges[y];
                for (var w in x) {
                    delete this.edges[w][y]
                }
                delete this.edges[y]
            }
        },
        removeAdjacence: function(x, w) {
            delete this.edges[x][w];
            delete this.edges[w][x]
        },
        hasNode: function(w) {
            return w in this.nodes
        },
        empty: function() {
            this.nodes = {};
            this.edges = {}
        }
    });
    var e = $jit.Graph;
    var j; (function() {
        var w = function(D, F, A, C, E) {
            var B;
            A = A || "current";
            D = "$" + (D ? D + "-": "");
            if (A == "current") {
                B = this.data
            } else {
                if (A == "start") {
                    B = this.startData
                } else {
                    if (A == "end") {
                        B = this.endData
                    }
                }
            }
            var z = D + F;
            if (C) {
                return B[z]
            }
            if (!this.Config.overridable) {
                return E[F] || 0
            }
            return (z in B) ? B[z] : ((z in this.data) ? this.data[z] : (E[F] || 0))
        };
        var y = function(C, D, B, z) {
            z = z || "current";
            C = "$" + (C ? C + "-": "");
            var A;
            if (z == "current") {
                A = this.data
            } else {
                if (z == "start") {
                    A = this.startData
                } else {
                    if (z == "end") {
                        A = this.endData
                    }
                }
            }
            A[C + D] = B
        };
        var x = function(B, z) {
            B = "$" + (B ? B + "-": "");
            var A = this;
            c.each(z,
            function(D) {
                var C = B + D;
                delete A.data[C];
                delete A.endData[C];
                delete A.startData[C]
            })
        };
        j = {
            getData: function(B, z, A) {
                return w.call(this, "", B, z, A, this.Config)
            },
            setData: function(B, A, z) {
                y.call(this, "", B, A, z)
            },
            setDataset: function(C, D) {
                C = c.splat(C);
                for (var z in D) {
                    for (var B = 0,
                    E = c.splat(D[z]), A = C.length; B < A; B++) {
                        this.setData(z, E[B], C[B])
                    }
                }
            },
            removeData: function() {
                x.call(this, "", Array.prototype.slice.call(arguments))
            },
            getCanvasStyle: function(B, z, A) {
                return w.call(this, "canvas", B, z, A, this.Config.CanvasStyles)
            },
            setCanvasStyle: function(B, A, z) {
                y.call(this, "canvas", B, A, z)
            },
            setCanvasStyles: function(C, D) {
                C = c.splat(C);
                for (var z in D) {
                    for (var B = 0,
                    E = c.splat(D[z]), A = C.length; B < A; B++) {
                        this.setCanvasStyle(z, E[B], C[B])
                    }
                }
            },
            removeCanvasStyle: function() {
                x.call(this, "canvas", Array.prototype.slice.call(arguments))
            },
            getLabelData: function(B, z, A) {
                return w.call(this, "label", B, z, A, this.Label)
            },
            setLabelData: function(B, A, z) {
                y.call(this, "label", B, A, z)
            },
            setLabelDataset: function(C, D) {
                C = c.splat(C);
                for (var z in D) {
                    for (var B = 0,
                    E = c.splat(D[z]), A = C.length; B < A; B++) {
                        this.setLabelData(z, E[B], C[B])
                    }
                }
            },
            removeLabelData: function() {
                x.call(this, "label", Array.prototype.slice.call(arguments))
            }
        }
    })();
    e.Node = new q({
        initialize: function(y, A, x, w, B) {
            var z = {
                id: "",
                name: "",
                data: {},
                startData: {},
                endData: {},
                adjacencies: {},
                selected: false,
                drawn: false,
                exist: false,
                angleSpan: {
                    begin: 0,
                    end: 0
                },
                pos: (A && r(0, 0)) || k(0, 0),
                startPos: (A && r(0, 0)) || k(0, 0),
                endPos: (A && r(0, 0)) || k(0, 0)
            };
            c.extend(this, c.extend(z, y));
            this.Config = this.Node = x;
            this.Edge = w;
            this.Label = B
        },
        adjacentTo: function(w) {
            return w.id in this.adjacencies
        },
        getAdjacency: function(w) {
            return this.adjacencies[w]
        },
        getPos: function(w) {
            w = w || "current";
            if (w == "current") {
                return this.pos
            } else {
                if (w == "end") {
                    return this.endPos
                } else {
                    if (w == "start") {
                        return this.startPos
                    }
                }
            }
        },
        setPos: function(x, w) {
            w = w || "current";
            var y;
            if (w == "current") {
                y = this.pos
            } else {
                if (w == "end") {
                    y = this.endPos
                } else {
                    if (w == "start") {
                        y = this.startPos
                    }
                }
            }
            y.set(x)
        }
    });
    e.Node.implement(j);
    e.Adjacence = new q({
        initialize: function(x, A, y, w, z) {
            this.nodeFrom = x;
            this.nodeTo = A;
            this.data = y || {};
            this.startData = {};
            this.endData = {};
            this.Config = this.Edge = w;
            this.Label = z
        }
    });
    e.Adjacence.implement(j);
    e.Util = {
        filter: function(x) {
            if (!x || !(c.type(x) == "string")) {
                return function() {
                    return true
                }
            }
            var w = x.split(" ");
            return function(z) {
                for (var y = 0; y < w.length; y++) {
                    if (z[w[y]]) {
                        return false
                    }
                }
                return true
            }
        },
        getNode: function(w, x) {
            return w.nodes[x]
        },
        eachNode: function(A, z, w) {
            var y = this.filter(w);
            for (var x in A.nodes) {
                if (y(A.nodes[x])) {
                    z(A.nodes[x])
                }
            }
        },
        eachAdjacency: function(B, C, x) {
            var y = B.adjacencies,
            A = this.filter(x);
            for (var D in y) {
                var w = y[D];
                if (A(w)) {
                    if (w.nodeFrom != B) {
                        var z = w.nodeFrom;
                        w.nodeFrom = w.nodeTo;
                        w.nodeTo = z
                    }
                    C(w, D)
                }
            }
        },
        computeLevels: function(C, D, z, y) {
            z = z || 0;
            var A = this.filter(y);
            this.eachNode(C,
            function(E) {
                E._flag = false;
                E._depth = -1
            },
            y);
            var x = C.getNode(D);
            x._depth = z;
            var w = [x];
            while (w.length != 0) {
                var B = w.pop();
                B._flag = true;
                this.eachAdjacency(B,
                function(E) {
                    var F = E.nodeTo;
                    if (F._flag == false && A(F)) {
                        if (F._depth < 0) {
                            F._depth = B._depth + 1 + z
                        }
                        w.unshift(F)
                    }
                },
                y)
            }
        },
        eachBFS: function(B, C, A, x) {
            var y = this.filter(x);
            this.clean(B);
            var w = [B.getNode(C)];
            while (w.length != 0) {
                var z = w.pop();
                z._flag = true;
                A(z, z._depth);
                this.eachAdjacency(z,
                function(D) {
                    var E = D.nodeTo;
                    if (E._flag == false && y(E)) {
                        E._flag = true;
                        w.unshift(E)
                    }
                },
                x)
            }
        },
        eachLevel: function(A, E, x, B, z) {
            var D = A._depth,
            w = this.filter(z),
            C = this;
            x = x === false ? Number.MAX_VALUE - D: x; (function y(H, F, G) {
                var I = H._depth;
                if (I >= F && I <= G && w(H)) {
                    B(H, I)
                }
                if (I < G) {
                    C.eachAdjacency(H,
                    function(J) {
                        var K = J.nodeTo;
                        if (K._depth > I) {
                            y(K, F, G)
                        }
                    })
                }
            })(A, E + D, x + D)
        },
        eachSubgraph: function(x, y, w) {
            this.eachLevel(x, 0, false, y, w)
        },
        eachSubnode: function(x, y, w) {
            this.eachLevel(x, 1, 1, y, w)
        },
        anySubnode: function(z, y, x) {
            var w = false;
            y = y || c.lambda(true);
            var A = c.type(y) == "string" ?
            function(B) {
                return B[y]
            }: y;
            this.eachSubnode(z,
            function(B) {
                if (A(B)) {
                    w = true
                }
            },
            x);
            return w
        },
        getSubnodes: function(B, C, w) {
            var y = [],
            A = this;
            C = C || 0;
            var z, x;
            if (c.type(C) == "array") {
                z = C[0];
                x = C[1]
            } else {
                z = C;
                x = Number.MAX_VALUE - B._depth
            }
            this.eachLevel(B, z, x,
            function(D) {
                y.push(D)
            },
            w);
            return y
        },
        getParents: function(x) {
            var w = [];
            this.eachAdjacency(x,
            function(y) {
                var z = y.nodeTo;
                if (z._depth < x._depth) {
                    w.push(z)
                }
            });
            return w
        },
        isDescendantOf: function(z, A) {
            if (z.id == A) {
                return true
            }
            var y = this.getParents(z),
            w = false;
            for (var x = 0; ! w && x < y.length; x++) {
                w = w || this.isDescendantOf(y[x], A)
            }
            return w
        },
        clean: function(w) {
            this.eachNode(w,
            function(x) {
                x._flag = false
            })
        },
        getClosestNodeToOrigin: function(x, y, w) {
            return this.getClosestNodeToPos(x, b.KER, y, w)
        },
        getClosestNodeToPos: function(y, B, A, w) {
            var x = null;
            A = A || "current";
            B = B && B.getc(true) || p.KER;
            var z = function(D, C) {
                var F = D.x - C.x,
                E = D.y - C.y;
                return F * F + E * E
            };
            this.eachNode(y,
            function(C) {
                x = (x == null || z(C.getPos(A).getc(true), B) < z(x.getPos(A).getc(true), B)) ? C: x
            },
            w);
            return x
        }
    };
    c.each(["getNode", "eachNode", "computeLevels", "eachBFS", "clean", "getClosestNodeToPos", "getClosestNodeToOrigin"],
    function(w) {
        e.prototype[w] = function() {
            return e.Util[w].apply(e.Util, [this].concat(Array.prototype.slice.call(arguments)))
        }
    });
    c.each(["eachAdjacency", "eachLevel", "eachSubgraph", "eachSubnode", "anySubnode", "getSubnodes", "getParents", "isDescendantOf"],
    function(w) {
        e.Node.prototype[w] = function() {
            return e.Util[w].apply(e.Util, [this].concat(Array.prototype.slice.call(arguments)))
        }
    });
    e.Op = {
        options: {
            type: "nothing",
            duration: 2000,
            hideLabels: true,
            fps: 30
        },
        initialize: function(w) {
            this.viz = w
        },
        removeNode: function(B, z) {
            var w = this.viz;
            var x = c.merge(this.options, w.controller, z);
            var D = c.splat(B);
            var y, A, C;
            switch (x.type) {
            case "nothing":
                for (y = 0; y < D.length; y++) {
                    w.graph.removeNode(D[y])
                }
                break;
            case "replot":
                this.removeNode(D, {
                    type: "nothing"
                });
                w.labels.clearLabels();
                w.refresh(true);
                break;
            case "fade:seq":
            case "fade":
                A = this;
                for (y = 0; y < D.length; y++) {
                    C = w.graph.getNode(D[y]);
                    C.setData("alpha", 0, "end")
                }
                w.fx.animate(c.merge(x, {
                    modes: ["node-property:alpha"],
                    onComplete: function() {
                        A.removeNode(D, {
                            type: "nothing"
                        });
                        w.labels.clearLabels();
                        w.reposition();
                        w.fx.animate(c.merge(x, {
                            modes: ["linear"]
                        }))
                    }
                }));
                break;
            case "fade:con":
                A = this;
                for (y = 0; y < D.length; y++) {
                    C = w.graph.getNode(D[y]);
                    C.setData("alpha", 0, "end");
                    C.ignore = true
                }
                w.reposition();
                w.fx.animate(c.merge(x, {
                    modes: ["node-property:alpha", "linear"],
                    onComplete: function() {
                        A.removeNode(D, {
                            type: "nothing"
                        })
                    }
                }));
                break;
            case "iter":
                A = this;
                w.fx.sequence({
                    condition: function() {
                        return D.length != 0
                    },
                    step: function() {
                        A.removeNode(D.shift(), {
                            type: "nothing"
                        });
                        w.labels.clearLabels()
                    },
                    onComplete: function() {
                        x.onComplete()
                    },
                    duration: Math.ceil(x.duration / D.length)
                });
                break;
            default:
                this.doError()
            }
        },
        removeEdge: function(D, B) {
            var w = this.viz;
            var z = c.merge(this.options, w.controller, B);
            var y = (c.type(D[0]) == "string") ? [D] : D;
            var A, C, x;
            switch (z.type) {
            case "nothing":
                for (A = 0; A < y.length; A++) {
                    w.graph.removeAdjacence(y[A][0], y[A][1])
                }
                break;
            case "replot":
                this.removeEdge(y, {
                    type: "nothing"
                });
                w.refresh(true);
                break;
            case "fade:seq":
            case "fade":
                C = this;
                for (A = 0; A < y.length; A++) {
                    x = w.graph.getAdjacence(y[A][0], y[A][1]);
                    if (x) {
                        x.setData("alpha", 0, "end")
                    }
                }
                w.fx.animate(c.merge(z, {
                    modes: ["edge-property:alpha"],
                    onComplete: function() {
                        C.removeEdge(y, {
                            type: "nothing"
                        });
                        w.reposition();
                        w.fx.animate(c.merge(z, {
                            modes: ["linear"]
                        }))
                    }
                }));
                break;
            case "fade:con":
                C = this;
                for (A = 0; A < y.length; A++) {
                    x = w.graph.getAdjacence(y[A][0], y[A][1]);
                    if (x) {
                        x.setData("alpha", 0, "end");
                        x.ignore = true
                    }
                }
                w.reposition();
                w.fx.animate(c.merge(z, {
                    modes: ["edge-property:alpha", "linear"],
                    onComplete: function() {
                        C.removeEdge(y, {
                            type: "nothing"
                        })
                    }
                }));
                break;
            case "iter":
                C = this;
                w.fx.sequence({
                    condition: function() {
                        return y.length != 0
                    },
                    step: function() {
                        C.removeEdge(y.shift(), {
                            type: "nothing"
                        });
                        w.labels.clearLabels()
                    },
                    onComplete: function() {
                        z.onComplete()
                    },
                    duration: Math.ceil(z.duration / y.length)
                });
                break;
            default:
                this.doError()
            }
        },
        sum: function(A, z) {
            var w = this.viz;
            var y = c.merge(this.options, w.controller, z),
            x = w.root;
            var C;
            w.root = z.id || w.root;
            switch (y.type) {
            case "nothing":
                C = w.construct(A);
                C.eachNode(function(E) {
                    E.eachAdjacency(function(F) {
                        w.graph.addAdjacence(F.nodeFrom, F.nodeTo, F.data)
                    })
                });
                break;
            case "replot":
                w.refresh(true);
                this.sum(A, {
                    type: "nothing"
                });
                w.refresh(true);
                break;
            case "fade:seq":
            case "fade":
            case "fade:con":
                that = this;
                C = w.construct(A);
                var D = this.preprocessSum(C);
                var B = !D ? ["node-property:alpha"] : ["node-property:alpha", "edge-property:alpha"];
                w.reposition();
                if (y.type != "fade:con") {
                    w.fx.animate(c.merge(y, {
                        modes: ["linear"],
                        onComplete: function() {
                            w.fx.animate(c.merge(y, {
                                modes: B,
                                onComplete: function() {
                                    y.onComplete()
                                }
                            }))
                        }
                    }))
                } else {
                    w.graph.eachNode(function(E) {
                        if (E.id != x && E.pos.getp().equals(b.KER)) {
                            E.pos.set(E.endPos);
                            E.startPos.set(E.endPos)
                        }
                    });
                    w.fx.animate(c.merge(y, {
                        modes: ["linear"].concat(B)
                    }))
                }
                break;
            default:
                this.doError()
            }
        },
        morph: function(E, x, z) {
            var B = this.viz;
            var F = c.merge(this.options, B.controller, x),
            A = B.root;
            var C;
            B.root = x.id || B.root;
            switch (F.type) {
            case "nothing":
                C = B.construct(E);
                C.eachNode(function(I) {
                    var H = B.graph.hasNode(I.id);
                    I.eachAdjacency(function(M) {
                        var L = !!B.graph.getAdjacence(M.nodeFrom.id, M.nodeTo.id);
                        B.graph.addAdjacence(M.nodeFrom, M.nodeTo, M.data);
                        if (L) {
                            var K = B.graph.getAdjacence(M.nodeFrom.id, M.nodeTo.id);
                            for (var N in (M.data || {})) {
                                K.data[N] = M.data[N]
                            }
                        }
                    });
                    if (H) {
                        var G = B.graph.getNode(I.id);
                        for (var J in (I.data || {})) {
                            G.data[J] = I.data[J]
                        }
                    }
                });
                B.graph.eachNode(function(G) {
                    G.eachAdjacency(function(H) {
                        if (!C.getAdjacence(H.nodeFrom.id, H.nodeTo.id)) {
                            B.graph.removeAdjacence(H.nodeFrom.id, H.nodeTo.id)
                        }
                    });
                    if (!C.hasNode(G.id)) {
                        B.graph.removeNode(G.id)
                    }
                });
                break;
            case "replot":
                B.labels.clearLabels(true);
                this.morph(E, {
                    type: "nothing"
                });
                B.refresh(true);
                B.refresh(true);
                break;
            case "fade:seq":
            case "fade":
            case "fade:con":
                that = this;
                C = B.construct(E);
                var D = z && ("node-property" in z) && c.map(c.splat(z["node-property"]),
                function(G) {
                    return "$" + G
                });
                B.graph.eachNode(function(H) {
                    var I = C.getNode(H.id);
                    if (!I) {
                        H.setData("alpha", 1);
                        H.setData("alpha", 1, "start");
                        H.setData("alpha", 0, "end");
                        H.ignore = true
                    } else {
                        var G = I.data;
                        for (var J in G) {
                            if (D && (c.indexOf(D, J) > -1)) {
                                H.endData[J] = G[J]
                            } else {
                                H.data[J] = G[J]
                            }
                        }
                    }
                });
                B.graph.eachNode(function(G) {
                    if (G.ignore) {
                        return
                    }
                    G.eachAdjacency(function(H) {
                        if (H.nodeFrom.ignore || H.nodeTo.ignore) {
                            return
                        }
                        var I = C.getNode(H.nodeFrom.id);
                        var J = C.getNode(H.nodeTo.id);
                        if (!I.adjacentTo(J)) {
                            var H = B.graph.getAdjacence(I.id, J.id);
                            w = true;
                            H.setData("alpha", 1);
                            H.setData("alpha", 1, "start");
                            H.setData("alpha", 0, "end")
                        }
                    })
                });
                var w = this.preprocessSum(C);
                var y = !w ? ["node-property:alpha"] : ["node-property:alpha", "edge-property:alpha"];
                y[0] = y[0] + ((z && ("node-property" in z)) ? (":" + c.splat(z["node-property"]).join(":")) : "");
                y[1] = (y[1] || "edge-property:alpha") + ((z && ("edge-property" in z)) ? (":" + c.splat(z["edge-property"]).join(":")) : "");
                if (z && ("label-property" in z)) {
                    y.push("label-property:" + c.splat(z["label-property"]).join(":"))
                }
                B.reposition();
                B.graph.eachNode(function(G) {
                    if (G.id != A && G.pos.getp().equals(b.KER)) {
                        G.pos.set(G.endPos);
                        G.startPos.set(G.endPos)
                    }
                });
                B.fx.animate(c.merge(F, {
                    modes: ["polar"].concat(y),
                    onComplete: function() {
                        B.graph.eachNode(function(G) {
                            if (G.ignore) {
                                B.graph.removeNode(G.id)
                            }
                        });
                        B.graph.eachNode(function(G) {
                            G.eachAdjacency(function(H) {
                                if (H.ignore) {
                                    B.graph.removeAdjacence(H.nodeFrom.id, H.nodeTo.id)
                                }
                            })
                        });
                        F.onComplete()
                    }
                }));
                break;
            default:
            }
        },
        contract: function(y, x) {
            var w = this.viz;
            if (y.collapsed || !y.anySubnode(c.lambda(true))) {
                return
            }
            x = c.merge(this.options, w.config, x || {},
            {
                modes: ["node-property:alpha:span", "linear"]
            });
            y.collapsed = true; (function z(A) {
                A.eachSubnode(function(B) {
                    B.ignore = true;
                    B.setData("alpha", 0, x.type == "animate" ? "end": "current");
                    z(B)
                })
            })(y);
            if (x.type == "animate") {
                w.compute("end");
                if (w.rotated) {
                    w.rotate(w.rotated, "none", {
                        property: "end"
                    })
                } (function z(A) {
                    A.eachSubnode(function(B) {
                        B.setPos(y.getPos("end"), "end");
                        z(B)
                    })
                })(y);
                w.fx.animate(x)
            } else {
                if (x.type == "replot") {
                    w.refresh()
                }
            }
        },
        expand: function(y, x) {
            if (! ("collapsed" in y)) {
                return
            }
            var w = this.viz;
            x = c.merge(this.options, w.config, x || {},
            {
                modes: ["node-property:alpha:span", "linear"]
            });
            delete y.collapsed; (function z(A) {
                A.eachSubnode(function(B) {
                    delete B.ignore;
                    B.setData("alpha", 1, x.type == "animate" ? "end": "current");
                    z(B)
                })
            })(y);
            if (x.type == "animate") {
                w.compute("end");
                if (w.rotated) {
                    w.rotate(w.rotated, "none", {
                        property: "end"
                    })
                }
                w.fx.animate(x)
            } else {
                if (x.type == "replot") {
                    w.refresh()
                }
            }
        },
        preprocessSum: function(x) {
            var w = this.viz;
            x.eachNode(function(z) {
                if (!w.graph.hasNode(z.id)) {
                    w.graph.addNode(z);
                    var A = w.graph.getNode(z.id);
                    A.setData("alpha", 0);
                    A.setData("alpha", 0, "start");
                    A.setData("alpha", 1, "end")
                }
            });
            var y = false;
            x.eachNode(function(z) {
                z.eachAdjacency(function(A) {
                    var B = w.graph.getNode(A.nodeFrom.id);
                    var C = w.graph.getNode(A.nodeTo.id);
                    if (!B.adjacentTo(C)) {
                        var A = w.graph.addAdjacence(B, C, A.data);
                        if (B.startAlpha == B.endAlpha && C.startAlpha == C.endAlpha) {
                            y = true;
                            A.setData("alpha", 0);
                            A.setData("alpha", 0, "start");
                            A.setData("alpha", 1, "end")
                        }
                    }
                })
            });
            return y
        }
    };
    var a = {
        none: {
            render: c.empty,
            contains: c.lambda(false)
        },
        circle: {
            render: function(z, A, w, y) {
                var x = y.getCtx();
                x.beginPath();
                x.arc(A.x, A.y, w, 0, Math.PI * 2, true);
                x.closePath();
                x[z]()
            },
            contains: function(B, A, w) {
                var y = B.x - A.x,
                x = B.y - A.y,
                z = y * y + x * x;
                return z <= w * w
            }
        },
        ellipse: {
            render: function(A, B, z, w, y) {
                var x = y.getCtx();
                w /= 2;
                z /= 2;
                x.save();
                x.scale(z / w, w / z);
                x.beginPath();
                x.arc(B.x * (w / z), B.y * (z / w), w, 0, Math.PI * 2, true);
                x.closePath();
                x[A]();
                x.restore()
            },
            contains: function(D, C, z, w) {
                z /= 2;
                w /= 2;
                var B = (z + w) / 2,
                y = D.x - C.x,
                x = D.y - C.y,
                A = y * y + x * x;
                return A <= B * B
            }
        },
        square: {
            render: function(x, z, y, w) {
                w.getCtx()[x + "Rect"](z.x - y, z.y - y, 2 * y, 2 * y)
            },
            contains: function(y, x, w) {
                return Math.abs(x.x - y.x) <= w && Math.abs(x.y - y.y) <= w
            }
        },
        rectangle: {
            render: function(z, A, y, w, x) {
                x.getCtx()[z + "Rect"](A.x - y / 2, A.y - w / 2, y, w)
            },
            contains: function(z, y, x, w) {
                return Math.abs(y.x - z.x) <= x / 2 && Math.abs(y.y - z.y) <= w / 2
            }
        },
        triangle: {
            render: function(C, D, z, w) {
                var G = w.getCtx(),
                y = D.x,
                x = D.y - z,
                F = y - z,
                E = D.y + z,
                B = y + z,
                A = E;
                G.beginPath();
                G.moveTo(y, x);
                G.lineTo(F, E);
                G.lineTo(B, A);
                G.closePath();
                G[C]()
            },
            contains: function(y, x, w) {
                return a.circle.contains(y, x, w)
            }
        },
        star: {
            render: function(A, C, B, x) {
                var w = x.getCtx(),
                z = Math.PI / 5;
                w.save();
                w.translate(C.x, C.y);
                w.beginPath();
                w.moveTo(B, 0);
                for (var y = 0; y < 9; y++) {
                    w.rotate(z);
                    if (y % 2 == 0) {
                        w.lineTo((B / 0.525731) * 0.200811, 0)
                    } else {
                        w.lineTo(B, 0)
                    }
                }
                w.closePath();
                w[A]();
                w.restore()
            },
            contains: function(y, x, w) {
                return a.circle.contains(y, x, w)
            }
        }
    };
    var m = {
        line: {
            render: function(z, y, x) {
                var w = x.getCtx();
                w.beginPath();
                w.moveTo(z.x, z.y);
                w.lineTo(y.x, y.y);
                w.stroke()
            },
            contains: function(G, y, B, E) {
                var z = Math.min,
                C = Math.max,
                x = z(G.x, y.x),
                F = C(G.x, y.x),
                w = z(G.y, y.y),
                D = C(G.y, y.y);
                if (B.x >= x && B.x <= F && B.y >= w && B.y <= D) {
                    if (Math.abs(y.x - G.x) <= E) {
                        return true
                    }
                    var A = (y.y - G.y) / (y.x - G.x) * (B.x - G.x) + G.y;
                    return Math.abs(A - B.y) <= E
                }
                return false
            }
        },
        arrow: {
            render: function(F, G, z, x, w) {
                var H = w.getCtx();
                if (x) {
                    var y = F;
                    F = G;
                    G = y
                }
                var C = new p(G.x - F.x, G.y - F.y);
                C.$scale(z / C.norm());
                var A = new p(G.x - C.x, G.y - C.y),
                B = new p( - C.y / 2, C.x / 2),
                E = A.add(B),
                D = A.$add(B.$scale( - 1));
                H.beginPath();
                H.moveTo(F.x, F.y);
                H.lineTo(G.x, G.y);
                H.stroke();
                H.beginPath();
                H.moveTo(E.x, E.y);
                H.lineTo(D.x, D.y);
                H.lineTo(G.x, G.y);
                H.closePath();
                H.fill()
            },
            contains: function(x, w, z, y) {
                return m.line.contains(x, w, z, y)
            }
        },
        hyperline: {
            render: function(D, E, w, y) {
                var F = y.getCtx();
                var z = A(D, E);
                if (z.a > 1000 || z.b > 1000 || z.ratio < 0) {
                    F.beginPath();
                    F.moveTo(D.x * w, D.y * w);
                    F.lineTo(E.x * w, E.y * w);
                    F.stroke()
                } else {
                    var C = Math.atan2(E.y - z.y, E.x - z.x);
                    var B = Math.atan2(D.y - z.y, D.x - z.x);
                    var x = x(C, B);
                    F.beginPath();
                    F.arc(z.x * w, z.y * w, z.ratio * w, C, B, x);
                    F.stroke()
                }
                function A(S, R) {
                    var K = (S.x * R.y - S.y * R.x),
                    G = K;
                    var J = S.squaredNorm(),
                    I = R.squaredNorm();
                    if (K == 0) {
                        return {
                            x: 0,
                            y: 0,
                            ratio: -1
                        }
                    }
                    var Q = (S.y * I - R.y * J + S.y - R.y) / K;
                    var O = (R.x * J - S.x * I + R.x - S.x) / G;
                    var P = -Q / 2;
                    var N = -O / 2;
                    var M = (Q * Q + O * O) / 4 - 1;
                    if (M < 0) {
                        return {
                            x: 0,
                            y: 0,
                            ratio: -1
                        }
                    }
                    var L = Math.sqrt(M);
                    var H = {
                        x: P,
                        y: N,
                        ratio: L > 1000 ? -1 : L,
                        a: Q,
                        b: O
                    };
                    return H
                }
                function x(G, H) {
                    return (G < H) ? ((G + Math.PI > H) ? false: true) : ((H + Math.PI > G) ? true: false)
                }
            },
            contains: c.lambda(false)
        }
    };
    e.Plot = {
        initialize: function(x, w) {
            this.viz = x;
            this.config = x.config;
            this.node = x.config.Node;
            this.edge = x.config.Edge;
            this.animation = new u;
            this.nodeTypes = new w.Plot.NodeTypes;
            this.edgeTypes = new w.Plot.EdgeTypes;
            this.labels = x.labels
        },
        nodeHelper: a,
        edgeHelper: m,
        Interpolator: {
            map: {
                border: "color",
                color: "color",
                width: "number",
                height: "number",
                dim: "number",
                alpha: "number",
                lineWidth: "number",
                angularWidth: "number",
                span: "number",
                valueArray: "array-number",
                dimArray: "array-number"
            },
            canvas: {
                globalAlpha: "number",
                fillStyle: "color",
                strokeStyle: "color",
                lineWidth: "number",
                shadowBlur: "number",
                shadowColor: "color",
                shadowOffsetX: "number",
                shadowOffsetY: "number",
                miterLimit: "number"
            },
            label: {
                size: "number",
                color: "color"
            },
            compute: function(y, x, w) {
                return y + (x - y) * w
            },
            moebius: function(D, C, F, z) {
                var B = z.scale( - F);
                if (B.norm() < 1) {
                    var w = B.x,
                    E = B.y;
                    var A = D.startPos.getc().moebiusTransformation(B);
                    D.pos.setc(A.x, A.y);
                    B.x = w;
                    B.y = E
                }
            },
            linear: function(x, w, A) {
                var z = x.startPos.getc(true);
                var y = x.endPos.getc(true);
                x.pos.setc(this.compute(z.x, y.x, A), this.compute(z.y, y.y, A))
            },
            polar: function(y, x, B) {
                var A = y.startPos.getp(true);
                var z = y.endPos.getp();
                var w = z.interpolate(A, B);
                y.pos.setp(w.theta, w.rho)
            },
            number: function(x, C, B, w, A) {
                var z = x[w](C, "start");
                var y = x[w](C, "end");
                x[A](C, this.compute(z, y, B))
            },
            color: function(y, w, E, B, z) {
                var C = c.hexToRgb(y[B](w, "start"));
                var D = c.hexToRgb(y[B](w, "end"));
                var A = this.compute;
                var x = c.rgbToHex([parseInt(A(C[0], D[0], E)), parseInt(A(C[1], D[1], E)), parseInt(A(C[2], D[2], E))]);
                y[z](w, x)
            },
            "array-number": function(z, y, J, G, B) {
                var H = z[G](y, "start"),
                I = z[G](y, "end"),
                K = [];
                for (var E = 0,
                A = H.length; E < A; E++) {
                    var x = H[E],
                    w = I[E];
                    if (x.length) {
                        for (var D = 0,
                        F = x.length,
                        C = []; D < F; D++) {
                            C.push(this.compute(x[D], w[D], J))
                        }
                        K.push(C)
                    } else {
                        K.push(this.compute(x, w, J))
                    }
                }
                z[B](y, K)
            },
            node: function(x, C, E, w, D, y) {
                w = this[w];
                if (C) {
                    var B = C.length;
                    for (var z = 0; z < B; z++) {
                        var A = C[z];
                        this[w[A]](x, A, E, D, y)
                    }
                } else {
                    for (var A in w) {
                        this[w[A]](x, A, E, D, y)
                    }
                }
            },
            edge: function(y, x, D, z, w, C) {
                var B = y.adjacencies;
                for (var A in B) {
                    this["node"](B[A], x, D, z, w, C)
                }
            },
            "node-property": function(x, w, y) {
                this["node"](x, w, y, "map", "getData", "setData")
            },
            "edge-property": function(x, w, y) {
                this["edge"](x, w, y, "map", "getData", "setData")
            },
            "label-property": function(x, w, y) {
                this["node"](x, w, y, "label", "getLabelData", "setLabelData")
            },
            "node-style": function(x, w, y) {
                this["node"](x, w, y, "canvas", "getCanvasStyle", "setCanvasStyle")
            },
            "edge-style": function(x, w, y) {
                this["edge"](x, w, y, "canvas", "getCanvasStyle", "setCanvasStyle")
            }
        },
        sequence: function(x) {
            var y = this;
            x = c.merge({
                condition: c.lambda(false),
                step: c.empty,
                onComplete: c.empty,
                duration: 200
            },
            x || {});
            var w = setInterval(function() {
                if (x.condition()) {
                    x.step()
                } else {
                    clearInterval(w);
                    x.onComplete()
                }
                y.viz.refresh(true)
            },
            x.duration)
        },
        prepare: function(C) {
            var B = this.viz.graph,
            z = {
                "node-property": {
                    getter: "getData",
                    setter: "setData"
                },
                "edge-property": {
                    getter: "getData",
                    setter: "setData"
                },
                "node-style": {
                    getter: "getCanvasStyle",
                    setter: "setCanvasStyle"
                },
                "edge-style": {
                    getter: "getCanvasStyle",
                    setter: "setCanvasStyle"
                }
            };
            var x = {};
            if (c.type(C) == "array") {
                for (var A = 0,
                w = C.length; A < w; A++) {
                    var y = C[A].split(":");
                    x[y.shift()] = y
                }
            } else {
                for (var D in C) {
                    if (D == "position") {
                        x[C.position] = []
                    } else {
                        x[D] = c.splat(C[D])
                    }
                }
            }
            B.eachNode(function(E) {
                E.startPos.set(E.pos);
                c.each(["node-property", "node-style"],
                function(H) {
                    if (H in x) {
                        var I = x[H];
                        for (var G = 0,
                        F = I.length; G < F; G++) {
                            E[z[H].setter](I[G], E[z[H].getter](I[G]), "start")
                        }
                    }
                });
                c.each(["edge-property", "edge-style"],
                function(F) {
                    if (F in x) {
                        var G = x[F];
                        E.eachAdjacency(function(I) {
                            for (var J = 0,
                            H = G.length; J < H; J++) {
                                I[z[F].setter](G[J], I[z[F].getter](G[J]), "start")
                            }
                        })
                    }
                })
            });
            return x
        },
        animate: function(z, y) {
            z = c.merge(this.viz.config, z || {});
            var A = this,
            x = this.viz,
            C = x.graph,
            D = this.Interpolator,
            B = z.type === "nodefx" ? this.nodeFxAnimation: this.animation;
            var w = this.prepare(z.modes);
            if (z.hideLabels) {
                this.labels.hideLabels(true)
            }
            B.setOptions(c.merge(z, {
                $animating: false,
                compute: function(E) {
                    C.eachNode(function(F) {
                        for (var G in w) {
                            D[G](F, w[G], E, y)
                        }
                    });
                    A.plot(z, this.$animating, E);
                    this.$animating = true
                },
                complete: function() {
                    if (z.hideLabels) {
                        A.labels.hideLabels(false)
                    }
                    A.plot(z);
                    z.onComplete();
                    z.onAfterCompute()
                }
            })).start()
        },
        nodeFx: function(y) {
            var D = this.viz,
            E = D.graph,
            B = this.nodeFxAnimation,
            F = c.merge(this.viz.config, {
                elements: {
                    id: false,
                    properties: {}
                },
                reposition: false
            });
            y = c.merge(F, y || {},
            {
                onBeforeCompute: c.empty,
                onAfterCompute: c.empty
            });
            B.stopTimer();
            var C = y.elements.properties;
            if (!y.elements.id) {
                E.eachNode(function(H) {
                    for (var G in C) {
                        H.setData(G, C[G], "end")
                    }
                })
            } else {
                var w = c.splat(y.elements.id);
                c.each(w,
                function(I) {
                    var H = E.getNode(I);
                    if (H) {
                        for (var G in C) {
                            H.setData(G, C[G], "end")
                        }
                    }
                })
            }
            var A = [];
            for (var x in C) {
                A.push(x)
            }
            var z = ["node-property:" + A.join(":")];
            if (y.reposition) {
                z.push("linear");
                D.compute("end")
            }
            this.animate(c.merge(y, {
                modes: z,
                type: "nodefx"
            }))
        },
        plot: function(x, G) {
            var E = this.viz,
            B = E.graph,
            y = E.canvas,
            w = E.root,
            C = this,
            F = y.getCtx(),
            A = Math.min,
            x = x || this.viz.controller;
            x.clearCanvas && y.clear();
            var D = B.getNode(w);
            if (!D) {
                return
            }
            var z = !!D.visited;
            B.eachNode(function(I) {
                var H = I.getData("alpha");
                I.eachAdjacency(function(J) {
                    var K = J.nodeTo;
                    if ( !! K.visited === z && I.drawn && K.drawn) { ! G && x.onBeforePlotLine(J);
                        F.save();
                        F.globalAlpha = A(H, K.getData("alpha"), J.getData("alpha"));
                        C.plotLine(J, y, G);
                        F.restore(); ! G && x.onAfterPlotLine(J)
                    }
                });
                F.save();
                if (I.drawn) { ! G && x.onBeforePlotNode(I);
                    C.plotNode(I, y, G); ! G && x.onAfterPlotNode(I)
                }
                if (!C.labelsHidden && x.withLabels) {
                    if (I.drawn && H >= 0.95) {
                        C.labels.plotLabel(y, I, x)
                    } else {
                        C.labels.hideLabel(I, false)
                    }
                }
                F.restore();
                I.visited = !z
            })
        },
        plotTree: function(A, x, E) {
            var B = this,
            C = this.viz,
            y = C.canvas,
            z = this.config,
            D = y.getCtx();
            var w = A.getData("alpha");
            A.eachSubnode(function(G) {
                if (x.plotSubtree(A, G) && G.exist && G.drawn) {
                    var F = A.getAdjacency(G.id); ! E && x.onBeforePlotLine(F);
                    D.globalAlpha = Math.min(w, G.getData("alpha"));
                    B.plotLine(F, y, E); ! E && x.onAfterPlotLine(F);
                    B.plotTree(G, x, E)
                }
            });
            if (A.drawn) { ! E && x.onBeforePlotNode(A);
                this.plotNode(A, y, E); ! E && x.onAfterPlotNode(A);
                if (!x.hideLabels && x.withLabels && w >= 0.95) {
                    this.labels.plotLabel(y, A, x)
                } else {
                    this.labels.hideLabel(A, false)
                }
            } else {
                this.labels.hideLabel(A, true)
            }
        },
        plotNode: function(y, x, F) {
            var C = y.getData("type"),
            B = this.node.CanvasStyles;
            if (C != "none") {
                var w = y.getData("lineWidth"),
                A = y.getData("color"),
                z = y.getData("alpha"),
                D = x.getCtx();
                D.lineWidth = w;
                D.fillStyle = D.strokeStyle = A;
                D.globalAlpha = z;
                for (var E in B) {
                    D[E] = y.getCanvasStyle(E)
                }
                this.nodeTypes[C].render.call(this, y, x, F)
            }
        },
        plotLine: function(B, x, E) {
            var A = B.getData("type"),
            z = this.edge.CanvasStyles;
            if (A != "none") {
                var w = B.getData("lineWidth"),
                y = B.getData("color"),
                C = x.getCtx();
                C.lineWidth = w;
                C.fillStyle = C.strokeStyle = y;
                for (var D in z) {
                    C[D] = B.getCanvasStyle(D)
                }
                this.edgeTypes[A].render.call(this, B, x, E)
            }
        }
    };
    e.Label = {};
    e.Label.Native = new q({
        plotLabel: function(y, z, x) {
            var w = y.getCtx();
            var A = z.pos.getc(true);
            w.font = z.getLabelData("style") + " " + z.getLabelData("size") + "px " + z.getLabelData("family");
            w.textAlign = z.getLabelData("textAlign");
            w.fillStyle = w.strokeStyle = z.getLabelData("color");
            w.textBaseline = z.getLabelData("textBaseline");
            this.renderLabel(y, z, x)
        },
        renderLabel: function(y, z, x) {
            var w = y.getCtx();
            var A = z.pos.getc(true);
            w.fillText(z.name, A.x, A.y + z.getData("height") / 2)
        },
        hideLabel: c.empty,
        hideLabels: c.empty
    });
    e.Label.DOM = new q({
        labelsHidden: false,
        labelContainer: false,
        labels: {},
        getLabelContainer: function() {
            return this.labelContainer ? this.labelContainer: this.labelContainer = document.getElementById(this.viz.config.labelContainer)
        },
        getLabel: function(w) {
            return (w in this.labels && this.labels[w] != null) ? this.labels[w] : this.labels[w] = document.getElementById(w)
        },
        hideLabels: function(x) {
            var w = this.getLabelContainer();
            if (x) {
                w.style.display = "none"
            } else {
                w.style.display = ""
            }
            this.labelsHidden = x
        },
        clearLabels: function(w) {
            for (var x in this.labels) {
                if (w || !this.viz.graph.hasNode(x)) {
                    this.disposeLabel(x);
                    delete this.labels[x]
                }
            }
        },
        disposeLabel: function(x) {
            var w = this.getLabel(x);
            if (w && w.parentNode) {
                w.parentNode.removeChild(w)
            }
        },
        hideLabel: function(A, w) {
            A = c.splat(A);
            var x = w ? "": "none",
            y,
            z = this;
            c.each(A,
            function(C) {
                var B = z.getLabel(C.id);
                if (B) {
                    B.style.display = x
                }
            })
        },
        fitsInCanvas: function(y, w) {
            var x = w.getSize();
            if (y.x >= x.width || y.x < 0 || y.y >= x.height || y.y < 0) {
                return false
            }
            return true
        }
    });
    e.Label.HTML = new q({
        Implements: e.Label.DOM,
        plotLabel: function(z, A, y) {
            var B = A.id,
            w = this.getLabel(B);
            if (!w && !(w = document.getElementById(B))) {
                w = document.createElement("div");
                var x = this.getLabelContainer();
                w.id = B;
                w.className = "node";
                w.style.position = "absolute";
                y.onCreateLabel(w, A);
                x.appendChild(w);
                this.labels[A.id] = w
            }
            this.placeLabel(w, A, y)
        }
    });
    e.Label.SVG = new q({
        Implements: e.Label.DOM,
        plotLabel: function(z, B, y) {
            var D = B.id,
            w = this.getLabel(D);
            if (!w && !(w = document.getElementById(D))) {
                var A = "http://www.w3.org/2000/svg";
                w = document.createElementNS(A, "svg:text");
                var C = document.createElementNS(A, "svg:tspan");
                w.appendChild(C);
                var x = this.getLabelContainer();
                w.setAttribute("id", D);
                w.setAttribute("class", "node");
                x.appendChild(w);
                y.onCreateLabel(w, B);
                this.labels[B.id] = w
            }
            this.placeLabel(w, B, y)
        }
    });
    e.Geom = new q({
        initialize: function(w) {
            this.viz = w;
            this.config = w.config;
            this.node = w.config.Node;
            this.edge = w.config.Edge
        },
        translate: function(x, w) {
            w = c.splat(w);
            this.viz.graph.eachNode(function(y) {
                c.each(w,
                function(z) {
                    y.getPos(z).$add(x)
                })
            })
        },
        setRightLevelToShow: function(z, w, B) {
            var A = this.getRightLevelToShow(z, w),
            y = this.viz.labels,
            x = c.merge({
                execShow: true,
                execHide: true,
                onHide: c.empty,
                onShow: c.empty
            },
            B || {});
            z.eachLevel(0, this.config.levelsToShow,
            function(D) {
                var C = D._depth - z._depth;
                if (C > A) {
                    x.onHide(D);
                    if (x.execHide) {
                        D.drawn = false;
                        D.exist = false;
                        y.hideLabel(D, false)
                    }
                } else {
                    x.onShow(D);
                    if (x.execShow) {
                        D.exist = true
                    }
                }
            });
            z.drawn = true
        },
        getRightLevelToShow: function(z, x) {
            var w = this.config;
            var A = w.levelsToShow;
            var y = w.constrained;
            if (!y) {
                return A
            }
            while (!this.treeFitsInCanvas(z, x, A) && A > 1) {
                A--
            }
            return A
        }
    });
    var d = {
        construct: function(x) {
            var y = (c.type(x) == "array");
            var w = new e(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
            if (!y) { (function(z, B) {
                    z.addNode(B);
                    if (B.children) {
                        for (var A = 0,
                        C = B.children; A < C.length; A++) {
                            z.addAdjacence(B, C[A]);
                            arguments.callee(z, C[A])
                        }
                    }
                })(w, x)
            } else { (function(H, I) {
                    var A = function(M) {
                        for (var L = 0,
                        J = I.length; L < J; L++) {
                            if (I[L].id == M) {
                                return I[L]
                            }
                        }
                        var K = {
                            id: M,
                            name: M
                        };
                        return H.addNode(K)
                    };
                    for (var E = 0,
                    B = I.length; E < B; E++) {
                        H.addNode(I[E]);
                        var F = I[E].adjacencies;
                        if (F) {
                            for (var C = 0,
                            G = F.length; C < G; C++) {
                                var z = F[C],
                                D = {};
                                if (typeof F[C] != "string") {
                                    D = c.merge(z.data, {});
                                    z = z.nodeTo
                                }
                                H.addAdjacence(I[E], A(z), D)
                            }
                        }
                    }
                })(w, x)
            }
            return w
        },
        loadJSON: function(x, w) {
            this.json = x;
            if (this.labels && this.labels.clearLabels) {
                this.labels.clearLabels(true)
            }
            this.graph = this.construct(x);
            if (c.type(x) != "array") {
                this.root = x.id
            } else {
                this.root = x[w ? w: 0].id
            }
        },
        toJSON: function(A) {
            A = A || "tree";
            if (A == "tree") {
                var y = {};
                var x = this.graph.getNode(this.root);
                var y = (function w(D) {
                    var B = {};
                    B.id = D.id;
                    B.name = D.name;
                    B.data = D.data;
                    var C = [];
                    D.eachSubnode(function(E) {
                        C.push(w(E))
                    });
                    B.children = C;
                    return B
                })(x);
                return y
            } else {
                var y = [];
                var z = !!this.graph.getNode(this.root).visited;
                this.graph.eachNode(function(C) {
                    var B = {};
                    B.id = C.id;
                    B.name = C.name;
                    B.data = C.data;
                    var D = [];
                    C.eachAdjacency(function(E) {
                        var G = E.nodeTo;
                        if ( !! G.visited === z) {
                            var F = {};
                            F.nodeTo = G.id;
                            F.data = E.data;
                            D.push(F)
                        }
                    });
                    B.adjacencies = D;
                    y.push(B);
                    C.visited = !z
                });
                return y
            }
        }
    };
    var g = $jit.Layouts = {};
    var f = {
        label: null,
        compute: function(z, A, x) {
            this.initializeLabel(x);
            var w = this.label,
            y = w.style;
            z.eachNode(function(D) {
                var H = D.getData("autoWidth"),
                I = D.getData("autoHeight");
                if (H || I) {
                    delete D.data.$width;
                    delete D.data.$height;
                    delete D.data.$dim;
                    var B = D.getData("width"),
                    J = D.getData("height");
                    y.width = H ? "auto": B + "px";
                    y.height = I ? "auto": J + "px";
                    w.innerHTML = D.name;
                    var F = w.offsetWidth,
                    C = w.offsetHeight;
                    var G = D.getData("type");
                    if (c.indexOf(["circle", "square", "triangle", "star"], G) === -1) {
                        D.setData("width", F);
                        D.setData("height", C)
                    } else {
                        var E = F > C ? F: C;
                        D.setData("width", E);
                        D.setData("height", E);
                        D.setData("dim", E)
                    }
                }
            })
        },
        initializeLabel: function(w) {
            if (!this.label) {
                this.label = document.createElement("div");
                document.body.appendChild(this.label)
            }
            this.setLabelStyles(w)
        },
        setLabelStyles: function(w) {
            c.extend(this.label.style, {
                visibility: "hidden",
                position: "absolute",
                width: "auto",
                height: "auto"
            });
            this.label.className = "jit-autoadjust-label"
        }
    };
    g.Tree = (function() {
        var F = Array.prototype.slice;
        function D(P, K, H, N, I) {
            var M = K.Node;
            var J = K.multitree;
            if (M.overridable) {
                var O = -1,
                L = -1;
                P.eachNode(function(S) {
                    if (S._depth == H && (!J || ("$orn" in S.data) && S.data.$orn == N)) {
                        var Q = S.getData("width", I);
                        var R = S.getData("height", I);
                        O = (O < Q) ? Q: O;
                        L = (L < R) ? R: L
                    }
                });
                return {
                    width: O < 0 ? M.width: O,
                    height: L < 0 ? M.height: L
                }
            } else {
                return M
            }
        }
        function G(I, L, K, H) {
            var J = (H == "left" || H == "right") ? "y": "x";
            I.getPos(L)[J] += K
        }
        function B(I, J) {
            var H = [];
            c.each(I,
            function(K) {
                K = F.call(K);
                K[0] += J;
                K[1] += J;
                H.push(K)
            });
            return H
        }
        function E(K, H) {
            if (K.length == 0) {
                return H
            }
            if (H.length == 0) {
                return K
            }
            var J = K.shift(),
            I = H.shift();
            return [[J[0], I[1]]].concat(E(K, H))
        }
        function z(H, I) {
            I = I || [];
            if (H.length == 0) {
                return I
            }
            var J = H.pop();
            return z(H, E(J, I))
        }
        function C(K, I, L, H, J) {
            if (K.length <= J || I.length <= J) {
                return 0
            }
            var N = K[J][1],
            M = I[J][0];
            return Math.max(C(K, I, L, H, ++J) + L, N - M + H)
        }
        function A(K, I, H) {
            function J(N, P, M) {
                if (P.length <= M) {
                    return []
                }
                var O = P[M],
                L = C(N, O, I, H, 0);
                return [L].concat(J(E(N, B(O, L)), P, ++M))
            }
            return J([], K, 0)
        }
        function x(L, K, J) {
            function H(O, Q, N) {
                if (Q.length <= N) {
                    return []
                }
                var P = Q[N],
                M = -C(P, O, K, J, 0);
                return [M].concat(H(E(B(P, M), O), Q, ++N))
            }
            L = F.call(L);
            var I = H([], L.reverse(), 0);
            return I.reverse()
        }
        function w(N, L, I, O) {
            var J = A(N, L, I),
            M = x(N, L, I);
            if (O == "left") {
                M = J
            } else {
                if (O == "right") {
                    J = M
                }
            }
            for (var K = 0,
            H = []; K < J.length; K++) {
                H[K] = (J[K] + M[K]) / 2
            }
            return H
        }
        function y(H, R, I, Y, W) {
            var K = Y.multitree;
            var Q = ["x", "y"],
            N = ["width", "height"];
            var J = +(W == "left" || W == "right");
            var O = Q[J],
            X = Q[1 - J];
            var T = Y.Node;
            var M = N[J],
            V = N[1 - J];
            var L = Y.siblingOffset;
            var U = Y.subtreeOffset;
            var S = Y.align;
            function P(ab, af, aj) {
                var aa = ab.getData(M, I);
                var ai = af || (ab.getData(V, I));
                var am = [],
                ak = [],
                ag = false;
                var Z = ai + Y.levelDistance;
                ab.eachSubnode(function(ao) {
                    if (ao.exist && (!K || ("$orn" in ao.data) && ao.data.$orn == W)) {
                        if (!ag) {
                            ag = D(H, Y, ao._depth, W, I)
                        }
                        var an = P(ao, ag[V], aj + Z);
                        am.push(an.tree);
                        ak.push(an.extent)
                    }
                });
                var ae = w(ak, U, L, S);
                for (var ad = 0,
                ac = [], ah = []; ad < am.length; ad++) {
                    G(am[ad], I, ae[ad], W);
                    ah.push(B(ak[ad], ae[ad]))
                }
                var al = [[ - aa / 2, aa / 2]].concat(z(ah));
                ab.getPos(I)[O] = 0;
                if (W == "top" || W == "left") {
                    ab.getPos(I)[X] = aj
                } else {
                    ab.getPos(I)[X] = -aj
                }
                return {
                    tree: ab,
                    extent: al
                }
            }
            P(R, false, 0)
        }
        return new q({
            compute: function(J, I) {
                var K = J || "start";
                var H = this.graph.getNode(this.root);
                c.extend(H, {
                    drawn: true,
                    exist: true,
                    selected: true
                });
                f.compute(this.graph, K, this.config);
                if ( !! I || !("_depth" in H)) {
                    this.graph.computeLevels(this.root, 0, "ignore")
                }
                this.computePositions(H, K)
            },
            computePositions: function(L, H) {
                var J = this.config;
                var I = J.multitree;
                var O = J.align;
                var K = O !== "center" && J.indent;
                var P = J.orientation;
                var N = I ? ["top", "right", "bottom", "left"] : [P];
                var M = this;
                c.each(N,
                function(Q) {
                    y(M.graph, L, H, M.config, Q, H);
                    var R = ["x", "y"][ + (Q == "left" || Q == "right")]; (function S(T) {
                        T.eachSubnode(function(U) {
                            if (U.exist && (!I || ("$orn" in U.data) && U.data.$orn == Q)) {
                                U.getPos(H)[R] += T.getPos(H)[R];
                                if (K) {
                                    U.getPos(H)[R] += O == "left" ? K: -K
                                }
                                S(U)
                            }
                        })
                    })(L)
                })
            }
        })
    })();
    $jit.ST = (function() {
        var x = [];
        function y(D) {
            D = D || this.clickedNode;
            if (!this.config.constrained) {
                return []
            }
            var A = this.geom;
            var H = this.graph;
            var B = this.canvas;
            var z = D._depth,
            E = [];
            H.eachNode(function(I) {
                if (I.exist && !I.selected) {
                    if (I.isDescendantOf(D.id)) {
                        if (I._depth <= z) {
                            E.push(I)
                        }
                    } else {
                        E.push(I)
                    }
                }
            });
            var F = A.getRightLevelToShow(D, B);
            D.eachLevel(F, F,
            function(I) {
                if (I.exist && !I.selected) {
                    E.push(I)
                }
            });
            for (var G = 0; G < x.length; G++) {
                var C = this.graph.getNode(x[G]);
                if (!C.isDescendantOf(D.id)) {
                    E.push(C)
                }
            }
            return E
        }
        function w(B) {
            var A = [],
            z = this.config;
            B = B || this.clickedNode;
            this.clickedNode.eachLevel(0, z.levelsToShow,
            function(C) {
                if (z.multitree && !("$orn" in C.data) && C.anySubnode(function(D) {
                    return D.exist && !D.drawn
                })) {
                    A.push(C)
                } else {
                    if (C.drawn && !C.anySubnode("drawn")) {
                        A.push(C)
                    }
                }
            });
            return A
        }
        return new q({
            Implements: [d, o, g.Tree],
            initialize: function(z) {
                var B = $jit.ST;
                var A = {
                    levelsToShow: 2,
                    levelDistance: 30,
                    constrained: true,
                    Node: {
                        type: "rectangle"
                    },
                    duration: 700,
                    offsetX: 0,
                    offsetY: 0
                };
                this.controller = this.config = c.merge(n("Canvas", "Fx", "Tree", "Node", "Edge", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), A, z);
                var C = this.config;
                if (C.useCanvas) {
                    this.canvas = C.useCanvas;
                    this.config.labelContainer = this.canvas.id + "-label"
                } else {
                    if (C.background) {
                        C.background = c.merge({
                            type: "Circles"
                        },
                        C.background)
                    }
                    this.canvas = new l(this, C);
                    this.config.labelContainer = (typeof C.injectInto == "string" ? C.injectInto: C.injectInto.id) + "-label"
                }
                this.graphOptions = {
                    complex: true
                };
                this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
                this.labels = new B.Label[C.Label.type](this);
                this.fx = new B.Plot(this, B);
                this.op = new B.Op(this);
                this.group = new B.Group(this);
                this.geom = new B.Geom(this);
                this.clickedNode = null;
                this.initializeExtras()
            },
            plot: function() {
                this.fx.plot(this.controller)
            },
            switchPosition: function(E, D, C) {
                var z = this.geom,
                A = this.fx,
                B = this;
                if (!A.busy) {
                    A.busy = true;
                    this.contract({
                        onComplete: function() {
                            z.switchOrientation(E);
                            B.compute("end", false);
                            A.busy = false;
                            if (D == "animate") {
                                B.onClick(B.clickedNode.id, C)
                            } else {
                                if (D == "replot") {
                                    B.select(B.clickedNode.id, C)
                                }
                            }
                        }
                    },
                    E)
                }
            },
            switchAlignment: function(B, A, z) {
                this.config.align = B;
                if (A == "animate") {
                    this.select(this.clickedNode.id, z)
                } else {
                    if (A == "replot") {
                        this.onClick(this.clickedNode.id, z)
                    }
                }
            },
            addNodeInPath: function(z) {
                x.push(z);
                this.select((this.clickedNode && this.clickedNode.id) || this.root)
            },
            clearNodesInPath: function(z) {
                x.length = 0;
                this.select((this.clickedNode && this.clickedNode.id) || this.root)
            },
            refresh: function() {
                this.reposition();
                this.select((this.clickedNode && this.clickedNode.id) || this.root)
            },
            reposition: function() {
                this.graph.computeLevels(this.root, 0, "ignore");
                this.geom.setRightLevelToShow(this.clickedNode, this.canvas);
                this.graph.eachNode(function(z) {
                    if (z.exist) {
                        z.drawn = true
                    }
                });
                this.compute("end")
            },
            requestNodes: function(B, C) {
                var A = c.merge(this.controller, C),
                z = this.config.levelsToShow;
                if (A.request) {
                    var E = [],
                    D = B._depth;
                    B.eachLevel(0, z,
                    function(F) {
                        if (F.drawn && !F.anySubnode()) {
                            E.push(F);
                            F._level = z - (F._depth - D)
                        }
                    });
                    this.group.requestNodes(E, A)
                } else {
                    A.onComplete()
                }
            },
            contract: function(D, E) {
                var C = this.config.orientation;
                var z = this.geom,
                B = this.group;
                if (E) {
                    z.switchOrientation(E)
                }
                var A = y.call(this);
                if (E) {
                    z.switchOrientation(C)
                }
                B.contract(A, c.merge(this.controller, D))
            },
            move: function(A, B) {
                this.compute("end", false);
                var z = B.Move,
                C = {
                    x: z.offsetX,
                    y: z.offsetY
                };
                if (z.enable) {
                    this.geom.translate(A.endPos.add(C).$scale( - 1), "end")
                }
                this.fx.animate(c.merge(this.controller, {
                    modes: ["linear"]
                },
                B))
            },
            expand: function(A, B) {
                var z = w.call(this, A);
                this.group.expand(z, c.merge(this.controller, B))
            },
            selectPath: function(C) {
                var B = this;
                this.graph.eachNode(function(E) {
                    E.selected = false
                });
                function D(F) {
                    if (F == null || F.selected) {
                        return
                    }
                    F.selected = true;
                    c.each(B.group.getSiblings([F])[F.id],
                    function(G) {
                        G.exist = true;
                        G.drawn = true
                    });
                    var E = F.getParents();
                    E = (E.length > 0) ? E[0] : null;
                    D(E)
                }
                for (var z = 0,
                A = [C.id].concat(x); z < A.length; z++) {
                    D(this.graph.getNode(A[z]))
                }
            },
            setRoot: function(G, F, E) {
                if (this.busy) {
                    return
                }
                this.busy = true;
                var D = this,
                B = this.canvas;
                var z = this.graph.getNode(this.root);
                var A = this.graph.getNode(G);
                function C() {
                    if (this.config.multitree && A.data.$orn) {
                        var I = A.data.$orn;
                        var J = {
                            left: "right",
                            right: "left",
                            top: "bottom",
                            bottom: "top"
                        } [I];
                        z.data.$orn = J; (function H(K) {
                            K.eachSubnode(function(L) {
                                if (L.id != G) {
                                    L.data.$orn = J;
                                    H(L)
                                }
                            })
                        })(z);
                        delete A.data.$orn
                    }
                    this.root = G;
                    this.clickedNode = A;
                    this.graph.computeLevels(this.root, 0, "ignore");
                    this.geom.setRightLevelToShow(A, B, {
                        execHide: false,
                        onShow: function(K) {
                            if (!K.drawn) {
                                K.drawn = true;
                                K.setData("alpha", 1, "end");
                                K.setData("alpha", 0);
                                K.pos.setc(A.pos.x, A.pos.y)
                            }
                        }
                    });
                    this.compute("end");
                    this.busy = true;
                    this.fx.animate({
                        modes: ["linear", "node-property:alpha"],
                        onComplete: function() {
                            D.busy = false;
                            D.onClick(G, {
                                onComplete: function() {
                                    E && E.onComplete()
                                }
                            })
                        }
                    })
                }
                delete z.data.$orns;
                if (F == "animate") {
                    C.call(this);
                    D.selectPath(A)
                } else {
                    if (F == "replot") {
                        C.call(this);
                        this.select(this.root)
                    }
                }
            },
            addSubtree: function(z, B, A) {
                if (B == "replot") {
                    this.op.sum(z, c.extend({
                        type: "replot"
                    },
                    A || {}))
                } else {
                    if (B == "animate") {
                        this.op.sum(z, c.extend({
                            type: "fade:seq"
                        },
                        A || {}))
                    }
                }
            },
            removeSubtree: function(E, A, D, C) {
                var B = this.graph.getNode(E),
                z = [];
                B.eachLevel( + !A, false,
                function(F) {
                    z.push(F.id)
                });
                if (D == "replot") {
                    this.op.removeNode(z, c.extend({
                        type: "replot"
                    },
                    C || {}))
                } else {
                    if (D == "animate") {
                        this.op.removeNode(z, c.extend({
                            type: "fade:seq"
                        },
                        C || {}))
                    }
                }
            },
            select: function(z, C) {
                var H = this.group,
                F = this.geom;
                var D = this.graph.getNode(z),
                B = this.canvas;
                var G = this.graph.getNode(this.root);
                var A = c.merge(this.controller, C);
                var E = this;
                A.onBeforeCompute(D);
                this.selectPath(D);
                this.clickedNode = D;
                this.requestNodes(D, {
                    onComplete: function() {
                        H.hide(H.prepare(y.call(E)), A);
                        F.setRightLevelToShow(D, B);
                        E.compute("current");
                        E.graph.eachNode(function(K) {
                            var J = K.pos.getc(true);
                            K.startPos.setc(J.x, J.y);
                            K.endPos.setc(J.x, J.y);
                            K.visited = false
                        });
                        var I = {
                            x: A.offsetX,
                            y: A.offsetY
                        };
                        E.geom.translate(D.endPos.add(I).$scale( - 1), ["start", "current", "end"]);
                        H.show(w.call(E));
                        E.plot();
                        A.onAfterCompute(E.clickedNode);
                        A.onComplete()
                    }
                })
            },
            onClick: function(A, H) {
                var C = this.canvas,
                G = this,
                z = this.geom,
                D = this.config;
                var F = {
                    Move: {
                        enable: true,
                        offsetX: D.offsetX || 0,
                        offsetY: D.offsetY || 0
                    },
                    setRightLevelToShowConfig: false,
                    onBeforeRequest: c.empty,
                    onBeforeContract: c.empty,
                    onBeforeMove: c.empty,
                    onBeforeExpand: c.empty
                };
                var B = c.merge(this.controller, F, H);
                if (!this.busy) {
                    this.busy = true;
                    var E = this.graph.getNode(A);
                    this.selectPath(E, this.clickedNode);
                    this.clickedNode = E;
                    B.onBeforeCompute(E);
                    B.onBeforeRequest(E);
                    this.requestNodes(E, {
                        onComplete: function() {
                            B.onBeforeContract(E);
                            G.contract({
                                onComplete: function() {
                                    z.setRightLevelToShow(E, C, B.setRightLevelToShowConfig);
                                    B.onBeforeMove(E);
                                    G.move(E, {
                                        Move: B.Move,
                                        onComplete: function() {
                                            B.onBeforeExpand(E);
                                            G.expand(E, {
                                                onComplete: function() {
                                                    G.busy = false;
                                                    B.onAfterCompute(A);
                                                    B.onComplete()
                                                }
                                            })
                                        }
                                    })
                                }
                            })
                        }
                    })
                }
            }
        })
    })();
    $jit.ST.$extend = true;
    $jit.ST.Op = new q({
        Implements: e.Op
    });
    $jit.ST.Group = new q({
        initialize: function(w) {
            this.viz = w;
            this.canvas = w.canvas;
            this.config = w.config;
            this.animation = new u;
            this.nodes = null
        },
        requestNodes: function(B, A) {
            var z = 0,
            x = B.length,
            D = {};
            var y = function() {
                A.onComplete()
            };
            var w = this.viz;
            if (x == 0) {
                y()
            }
            for (var C = 0; C < x; C++) {
                D[B[C].id] = B[C];
                A.request(B[C].id, B[C]._level, {
                    onComplete: function(F, E) {
                        if (E && E.children) {
                            E.id = F;
                            w.op.sum(E, {
                                type: "nothing"
                            })
                        }
                        if (++z == x) {
                            w.graph.computeLevels(w.root, 0);
                            y()
                        }
                    }
                })
            }
        },
        contract: function(y, x) {
            var w = this.viz;
            var z = this;
            y = this.prepare(y);
            this.animation.setOptions(c.merge(x, {
                $animating: false,
                compute: function(A) {
                    if (A == 1) {
                        A = 0.99
                    }
                    z.plotStep(1 - A, x, this.$animating);
                    this.$animating = "contract"
                },
                complete: function() {
                    z.hide(y, x)
                }
            })).start()
        },
        hide: function(y, x) {
            var w = this.viz;
            for (var z = 0; z < y.length; z++) {
                if (true || !x || !x.request) {
                    y[z].eachLevel(1, false,
                    function(B) {
                        if (B.exist) {
                            c.extend(B, {
                                drawn: false,
                                exist: false
                            })
                        }
                    })
                } else {
                    var A = [];
                    y[z].eachLevel(1, false,
                    function(B) {
                        A.push(B.id)
                    });
                    w.op.removeNode(A, {
                        type: "nothing"
                    });
                    w.labels.clearLabels()
                }
            }
            x.onComplete()
        },
        expand: function(x, w) {
            var y = this;
            this.show(x);
            this.animation.setOptions(c.merge(w, {
                $animating: false,
                compute: function(z) {
                    y.plotStep(z, w, this.$animating);
                    this.$animating = "expand"
                },
                complete: function() {
                    y.plotStep(undefined, w, false);
                    w.onComplete()
                }
            })).start()
        },
        show: function(w) {
            var x = this.config;
            this.prepare(w);
            c.each(w,
            function(z) {
                if (x.multitree && !("$orn" in z.data)) {
                    delete z.data.$orns;
                    var y = " ";
                    z.eachSubnode(function(A) {
                        if (("$orn" in A.data) && y.indexOf(A.data.$orn) < 0 && A.exist && !A.drawn) {
                            y += A.data.$orn + " "
                        }
                    });
                    z.data.$orns = y
                }
                z.eachLevel(0, x.levelsToShow,
                function(A) {
                    if (A.exist) {
                        A.drawn = true
                    }
                })
            })
        },
        prepare: function(w) {
            this.nodes = this.getNodesWithChildren(w);
            return this.nodes
        },
        getNodesWithChildren: function(y) {
            var x = [],
            A = this.config,
            w = this.viz.root;
            y.sort(function(E, D) {
                return (E._depth <= D._depth) - (E._depth >= D._depth)
            });
            for (var B = 0; B < y.length; B++) {
                if (y[B].anySubnode("exist")) {
                    for (var z = B + 1,
                    C = false; ! C && z < y.length; z++) {
                        if (!A.multitree || "$orn" in y[z].data) {
                            C = C || y[B].isDescendantOf(y[z].id)
                        }
                    }
                    if (!C) {
                        x.push(y[B])
                    }
                }
            }
            return x
        },
        plotStep: function(G, C, I) {
            var F = this.viz,
            z = this.config,
            y = F.canvas,
            H = y.getCtx(),
            w = this.nodes;
            var B, A;
            var x = {};
            for (B = 0; B < w.length; B++) {
                A = w[B];
                x[A.id] = [];
                var E = z.multitree && !("$orn" in A.data);
                var D = E && A.data.$orns;
                A.eachSubgraph(function(J) {
                    if (E && D && D.indexOf(J.data.$orn) > 0 && J.drawn) {
                        J.drawn = false;
                        x[A.id].push(J)
                    } else {
                        if ((!E || !D) && J.drawn) {
                            J.drawn = false;
                            x[A.id].push(J)
                        }
                    }
                });
                A.drawn = true
            }
            if (w.length > 0) {
                F.fx.plot()
            }
            for (B in x) {
                c.each(x[B],
                function(J) {
                    J.drawn = true
                })
            }
            for (B = 0; B < w.length; B++) {
                A = w[B];
                H.save();
                F.fx.plotSubtree(A, C, G, I);
                H.restore()
            }
        },
        getSiblings: function(w) {
            var x = {};
            c.each(w,
            function(A) {
                var z = A.getParents();
                if (z.length == 0) {
                    x[A.id] = [A]
                } else {
                    var y = [];
                    z[0].eachSubnode(function(B) {
                        y.push(B)
                    });
                    x[A.id] = y
                }
            });
            return x
        }
    });
    $jit.ST.Geom = new q({
        Implements: e.Geom,
        switchOrientation: function(w) {
            this.config.orientation = w
        },
        dispatch: function() {
            var x = Array.prototype.slice.call(arguments);
            var y = x.shift(),
            w = x.length;
            var z = function(A) {
                return typeof A == "function" ? A() : A
            };
            if (w == 2) {
                return (y == "top" || y == "bottom") ? z(x[0]) : z(x[1])
            } else {
                if (w == 4) {
                    switch (y) {
                    case "top":
                        return z(x[0]);
                    case "right":
                        return z(x[1]);
                    case "bottom":
                        return z(x[2]);
                    case "left":
                        return z(x[3])
                    }
                }
            }
            return undefined
        },
        getSize: function(E, D) {
            var C = E.data,
            z = this.config;
            var y = z.siblingOffset;
            var B = (z.multitree && ("$orn" in C) && C.$orn) || z.orientation;
            var x = E.getData("width") + y;
            var A = E.getData("height") + y;
            if (!D) {
                return this.dispatch(B, A, x)
            } else {
                return this.dispatch(B, x, A)
            }
        },
        getTreeBaseSize: function(A, B, x) {
            var y = this.getSize(A, true),
            w = 0,
            z = this;
            if (x(B, A)) {
                return y
            }
            if (B === 0) {
                return 0
            }
            A.eachSubnode(function(C) {
                w += z.getTreeBaseSize(C, B - 1, x)
            });
            return (y > w ? y: w) + this.config.subtreeOffset
        },
        getEdge: function(C, B, A) {
            var y = function(E, w) {
                return function() {
                    return C.pos.add(new p(E, w))
                }
            };
            var D = this.node;
            var x = C.getData("width");
            var z = C.getData("height");
            if (B == "begin") {
                if (D.align == "center") {
                    return this.dispatch(A, y(0, z / 2), y( - x / 2, 0), y(0, -z / 2), y(x / 2, 0))
                } else {
                    if (D.align == "left") {
                        return this.dispatch(A, y(0, z), y(0, 0), y(0, 0), y(x, 0))
                    } else {
                        if (D.align == "right") {
                            return this.dispatch(A, y(0, 0), y( - x, 0), y(0, -z), y(0, 0))
                        } else {
                            throw "align: not implemented"
                        }
                    }
                }
            } else {
                if (B == "end") {
                    if (D.align == "center") {
                        return this.dispatch(A, y(0, -z / 2), y(x / 2, 0), y(0, z / 2), y( - x / 2, 0))
                    } else {
                        if (D.align == "left") {
                            return this.dispatch(A, y(0, 0), y(x, 0), y(0, z), y(0, 0))
                        } else {
                            if (D.align == "right") {
                                return this.dispatch(A, y(0, -z), y(0, 0), y(0, 0), y( - x, 0))
                            } else {
                                throw "align: not implemented"
                            }
                        }
                    }
                }
            }
        },
        getScaledTreePosition: function(B, D) {
            var C = this.node;
            var x = B.getData("width");
            var A = B.getData("height");
            var z = (this.config.multitree && ("$orn" in B.data) && B.data.$orn) || this.config.orientation;
            var y = function(E, w) {
                return function() {
                    return B.pos.add(new p(E, w)).$scale(1 - D)
                }
            };
            if (C.align == "left") {
                return this.dispatch(z, y(0, A), y(0, 0), y(0, 0), y(x, 0))
            } else {
                if (C.align == "center") {
                    return this.dispatch(z, y(0, A / 2), y( - x / 2, 0), y(0, -A / 2), y(x / 2, 0))
                } else {
                    if (C.align == "right") {
                        return this.dispatch(z, y(0, 0), y( - x, 0), y(0, -A), y(0, 0))
                    } else {
                        throw "align: not implemented"
                    }
                }
            }
        },
        treeFitsInCanvas: function(B, w, C) {
            var y = w.getSize();
            var z = (this.config.multitree && ("$orn" in B.data) && B.data.$orn) || this.config.orientation;
            var x = this.dispatch(z, y.width, y.height);
            var A = this.getTreeBaseSize(B, C,
            function(E, D) {
                return E === 0 || !D.anySubnode()
            });
            return (A < x)
        }
    });
    $jit.ST.Plot = new q({
        Implements: e.Plot,
        plotSubtree: function(z, w, A, E) {
            var C = this.viz,
            x = C.canvas,
            y = C.config;
            A = Math.min(Math.max(0.001, A), 1);
            if (A >= 0) {
                z.drawn = false;
                var D = x.getCtx();
                var B = C.geom.getScaledTreePosition(z, A);
                D.translate(B.x, B.y);
                D.scale(A, A)
            }
            this.plotTree(z, c.merge(w, {
                withLabels: true,
                hideLabels: !!A,
                plotSubtree: function(I, G) {
                    var F = y.multitree && !("$orn" in z.data);
                    var H = F && z.getData("orns");
                    return ! F || H.indexOf(elem.getData("orn")) > -1
                }
            }), E);
            if (A >= 0) {
                z.drawn = true
            }
        },
        getAlignedPos: function(B, z, w) {
            var y = this.node;
            var A, x;
            if (y.align == "center") {
                A = {
                    x: B.x - z / 2,
                    y: B.y - w / 2
                }
            } else {
                if (y.align == "left") {
                    x = this.config.orientation;
                    if (x == "bottom" || x == "top") {
                        A = {
                            x: B.x - z / 2,
                            y: B.y
                        }
                    } else {
                        A = {
                            x: B.x,
                            y: B.y - w / 2
                        }
                    }
                } else {
                    if (y.align == "right") {
                        x = this.config.orientation;
                        if (x == "bottom" || x == "top") {
                            A = {
                                x: B.x - z / 2,
                                y: B.y - w
                            }
                        } else {
                            A = {
                                x: B.x - z,
                                y: B.y - w / 2
                            }
                        }
                    } else {
                        throw "align: not implemented"
                    }
                }
            }
            return A
        },
        getOrientation: function(w) {
            var y = this.config;
            var x = y.orientation;
            if (y.multitree) {
                var z = w.nodeFrom;
                var A = w.nodeTo;
                x = (("$orn" in z.data) && z.data.$orn) || (("$orn" in A.data) && A.data.$orn)
            }
            return x
        }
    });
    $jit.ST.Label = {};
    $jit.ST.Label.Native = new q({
        Implements: e.Label.Native,
        renderLabel: function(y, z, x) {
            var w = y.getCtx();
            var A = z.pos.getc(true);
            w.fillText(z.name, A.x, A.y)
        }
    });
    $jit.ST.Label.DOM = new q({
        Implements: e.Label.DOM,
        placeLabel: function(P, J, F) {
            var B = J.pos.getc(true),
            O = this.viz.config,
            K = O.Node,
            x = this.viz.canvas,
            C = J.getData("width"),
            M = J.getData("height"),
            y = x.getSize(),
            G,
            N;
            var A = x.translateOffsetX,
            z = x.translateOffsetY,
            E = x.scaleOffsetX,
            D = x.scaleOffsetY,
            I = B.x * E + A,
            H = B.y * D + z;
            if (K.align == "center") {
                G = {
                    x: Math.round(I - C / 2 + y.width / 2),
                    y: Math.round(H - M / 2 + y.height / 2)
                }
            } else {
                if (K.align == "left") {
                    N = O.orientation;
                    if (N == "bottom" || N == "top") {
                        G = {
                            x: Math.round(I - C / 2 + y.width / 2),
                            y: Math.round(H + y.height / 2)
                        }
                    } else {
                        G = {
                            x: Math.round(I + y.width / 2),
                            y: Math.round(H - M / 2 + y.height / 2)
                        }
                    }
                } else {
                    if (K.align == "right") {
                        N = O.orientation;
                        if (N == "bottom" || N == "top") {
                            G = {
                                x: Math.round(I - C / 2 + y.width / 2),
                                y: Math.round(H - M + y.height / 2)
                            }
                        } else {
                            G = {
                                x: Math.round(I - C + y.width / 2),
                                y: Math.round(H - M / 2 + y.height / 2)
                            }
                        }
                    } else {
                        throw "align: not implemented"
                    }
                }
            }
            var L = P.style;
            L.left = G.x + "px";
            L.top = G.y + "px";
            L.display = this.fitsInCanvas(G, x) ? "": "none";
            F.onPlaceLabel(P, J)
        }
    });
    $jit.ST.Label.SVG = new q({
        Implements: [$jit.ST.Label.DOM, e.Label.SVG],
        initialize: function(w) {
            this.viz = w
        }
    });
    $jit.ST.Label.HTML = new q({
        Implements: [$jit.ST.Label.DOM, e.Label.HTML],
        initialize: function(w) {
            this.viz = w
        }
    });
    $jit.ST.Plot.NodeTypes = new q({
        none: {
            render: c.empty,
            contains: c.lambda(false)
        },
        circle: {
            render: function(x, w) {
                var z = x.getData("dim"),
                A = this.getAlignedPos(x.pos.getc(true), z, z),
                y = z / 2;
                this.nodeHelper.circle.render("fill", {
                    x: A.x + y,
                    y: A.y + y
                },
                y, w)
            },
            contains: function(w, A) {
                var y = w.getData("dim"),
                z = this.getAlignedPos(w.pos.getc(true), y, y),
                x = y / 2;
                this.nodeHelper.circle.contains({
                    x: z.x + x,
                    y: z.y + x
                },
                x)
            }
        },
        square: {
            render: function(x, w) {
                var z = x.getData("dim"),
                y = z / 2,
                A = this.getAlignedPos(x.pos.getc(true), z, z);
                this.nodeHelper.square.render("fill", {
                    x: A.x + y,
                    y: A.y + y
                },
                y, w)
            },
            contains: function(w, A) {
                var y = w.getData("dim"),
                z = this.getAlignedPos(w.pos.getc(true), y, y),
                x = y / 2;
                this.nodeHelper.square.contains({
                    x: z.x + x,
                    y: z.y + x
                },
                x)
            }
        },
        ellipse: {
            render: function(z, x) {
                var y = z.getData("width"),
                w = z.getData("height"),
                A = this.getAlignedPos(z.pos.getc(true), y, w);
                this.nodeHelper.ellipse.render("fill", {
                    x: A.x + y / 2,
                    y: A.y + w / 2
                },
                y, w, x)
            },
            contains: function(y, A) {
                var x = y.getData("width"),
                w = y.getData("height"),
                z = this.getAlignedPos(y.pos.getc(true), x, w);
                this.nodeHelper.ellipse.contains({
                    x: z.x + x / 2,
                    y: z.y + w / 2
                },
                x, w, canvas)
            }
        },
        rectangle: {
            render: function(z, x) {
                var y = z.getData("width"),
                w = z.getData("height"),
                A = this.getAlignedPos(z.pos.getc(true), y, w);
                this.nodeHelper.rectangle.render("fill", {
                    x: A.x + y / 2,
                    y: A.y + w / 2
                },
                y, w, x)
            },
            contains: function(y, A) {
                var x = y.getData("width"),
                w = y.getData("height"),
                z = this.getAlignedPos(y.pos.getc(true), x, w);
                this.nodeHelper.rectangle.contains({
                    x: z.x + x / 2,
                    y: z.y + w / 2
                },
                x, w, canvas)
            }
        }
    });
    $jit.ST.Plot.EdgeTypes = new q({
        none: c.empty,
        line: {
            render: function(x, z) {
                var y = this.getOrientation(x),
                A = x.nodeFrom,
                B = x.nodeTo,
                w = A._depth < B._depth,
                D = this.viz.geom.getEdge(w ? A: B, "begin", y),
                C = this.viz.geom.getEdge(w ? B: A, "end", y);
                this.edgeHelper.line.render(D, C, z)
            },
            contains: function(x, D) {
                var y = this.getOrientation(x),
                z = x.nodeFrom,
                A = x.nodeTo,
                w = z._depth < A._depth,
                C = this.viz.geom.getEdge(w ? z: A, "begin", y),
                B = this.viz.geom.getEdge(w ? A: z, "end", y);
                return this.edgeHelper.line.contains(C, B, D, this.edge.epsilon)
            }
        },
        arrow: {
            render: function(C, x) {
                var B = this.getOrientation(C),
                y = C.nodeFrom,
                w = C.nodeTo,
                A = C.getData("dim"),
                E = this.viz.geom.getEdge(y, "begin", B),
                F = this.viz.geom.getEdge(w, "end", B),
                D = C.data.$direction,
                z = (D && D.length > 1 && D[0] != y.id);
                this.edgeHelper.arrow.render(E, F, A, z, x)
            },
            contains: function(x, D) {
                var y = this.getOrientation(x),
                z = x.nodeFrom,
                A = x.nodeTo,
                w = z._depth < A._depth,
                C = this.viz.geom.getEdge(w ? z: A, "begin", y),
                B = this.viz.geom.getEdge(w ? A: z, "end", y);
                return this.edgeHelper.arrow.contains(C, B, D, this.edge.epsilon)
            }
        },
        "quadratic:begin": {
            render: function(C, w) {
                var B = this.getOrientation(C);
                var A = C.nodeFrom,
                D = C.nodeTo,
                F = A._depth < D._depth,
                x = this.viz.geom.getEdge(F ? A: D, "begin", B),
                y = this.viz.geom.getEdge(F ? D: A, "end", B),
                z = C.getData("dim"),
                E = w.getCtx();
                E.beginPath();
                E.moveTo(x.x, x.y);
                switch (B) {
                case "left":
                    E.quadraticCurveTo(x.x + z, x.y, y.x, y.y);
                    break;
                case "right":
                    E.quadraticCurveTo(x.x - z, x.y, y.x, y.y);
                    break;
                case "top":
                    E.quadraticCurveTo(x.x, x.y + z, y.x, y.y);
                    break;
                case "bottom":
                    E.quadraticCurveTo(x.x, x.y - z, y.x, y.y);
                    break
                }
                E.stroke()
            }
        },
        "quadratic:end": {
            render: function(C, w) {
                var B = this.getOrientation(C);
                var A = C.nodeFrom,
                D = C.nodeTo,
                F = A._depth < D._depth,
                x = this.viz.geom.getEdge(F ? A: D, "begin", B),
                y = this.viz.geom.getEdge(F ? D: A, "end", B),
                z = C.getData("dim"),
                E = w.getCtx();
                E.beginPath();
                E.moveTo(x.x, x.y);
                switch (B) {
                case "left":
                    E.quadraticCurveTo(y.x - z, y.y, y.x, y.y);
                    break;
                case "right":
                    E.quadraticCurveTo(y.x + z, y.y, y.x, y.y);
                    break;
                case "top":
                    E.quadraticCurveTo(y.x, y.y - z, y.x, y.y);
                    break;
                case "bottom":
                    E.quadraticCurveTo(y.x, y.y + z, y.x, y.y);
                    break
                }
                E.stroke()
            }
        },
        bezier: {
            render: function(C, w) {
                var B = this.getOrientation(C),
                A = C.nodeFrom,
                D = C.nodeTo,
                F = A._depth < D._depth,
                x = this.viz.geom.getEdge(F ? A: D, "begin", B),
                y = this.viz.geom.getEdge(F ? D: A, "end", B),
                z = C.getData("dim"),
                E = w.getCtx();
                E.beginPath();
                E.moveTo(x.x, x.y);
                switch (B) {
                case "left":
                    E.bezierCurveTo(x.x + z, x.y, y.x - z, y.y, y.x, y.y);
                    break;
                case "right":
                    E.bezierCurveTo(x.x - z, x.y, y.x + z, y.y, y.x, y.y);
                    break;
                case "top":
                    E.bezierCurveTo(x.x, x.y + z, y.x, y.y - z, y.x, y.y);
                    break;
                case "bottom":
                    E.bezierCurveTo(x.x, x.y - z, y.x, y.y + z, y.x, y.y);
                    break
                }
                E.stroke()
            }
        }
    });
    $jit.ST.Plot.NodeTypes.implement({
        "areachart-stacked": {
            render: function(V, D) {
                var T = V.pos.getc(true),
                w = V.getData("width"),
                A = V.getData("height"),
                G = this.getAlignedPos(T, w, A),
                aa = G.x,
                Z = G.y,
                L = V.getData("stringArray"),
                F = V.getData("dimArray"),
                B = V.getData("valueArray"),
                ac = c.reduce(B,
                function(ai, aj) {
                    return ai + aj[0]
                },
                0),
                ab = c.reduce(B,
                function(ai, aj) {
                    return ai + aj[1]
                },
                0),
                I = V.getData("colorArray"),
                C = I.length,
                X = V.getData("config"),
                J = V.getData("gradient"),
                ah = X.showLabels,
                N = X.showAggregates,
                ad = X.Label,
                S = V.getData("prev");
                var M = D.getCtx(),
                H = V.getData("border");
                if (I && F && L) {
                    for (var ag = 0,
                    ae = F.length,
                    K = 0,
                    E = 0,
                    W = 0; ag < ae; ag++) {
                        M.fillStyle = M.strokeStyle = I[ag % C];
                        M.save();
                        if (J && (F[ag][0] > 0 || F[ag][1] > 0)) {
                            var Q = K + F[ag][0],
                            O = E + F[ag][1],
                            af = Math.atan((O - Q) / w),
                            Y = 55;
                            var U = M.createLinearGradient(aa + w / 2, Z - (Q + O) / 2, aa + w / 2 + Y * Math.sin(af), Z - (Q + O) / 2 + Y * Math.cos(af));
                            var P = c.rgbToHex(c.map(c.hexToRgb(I[ag % C].slice(1)),
                            function(x) {
                                return (x * 0.85) >> 0
                            }));
                            U.addColorStop(0, I[ag % C]);
                            U.addColorStop(1, P);
                            M.fillStyle = U
                        }
                        M.beginPath();
                        M.moveTo(aa, Z - K);
                        M.lineTo(aa + w, Z - E);
                        M.lineTo(aa + w, Z - E - F[ag][1]);
                        M.lineTo(aa, Z - K - F[ag][0]);
                        M.lineTo(aa, Z - K);
                        M.fill();
                        M.restore();
                        if (H) {
                            var R = H.name == L[ag];
                            var z = R ? 0.7 : 0.8;
                            var P = c.rgbToHex(c.map(c.hexToRgb(I[ag % C].slice(1)),
                            function(x) {
                                return (x * z) >> 0
                            }));
                            M.strokeStyle = P;
                            M.lineWidth = R ? 4 : 1;
                            M.save();
                            M.beginPath();
                            if (H.index === 0) {
                                M.moveTo(aa, Z - K);
                                M.lineTo(aa, Z - K - F[ag][0])
                            } else {
                                M.moveTo(aa + w, Z - E);
                                M.lineTo(aa + w, Z - E - F[ag][1])
                            }
                            M.stroke();
                            M.restore()
                        }
                        K += (F[ag][0] || 0);
                        E += (F[ag][1] || 0);
                        if (F[ag][0] > 0) {
                            W += (B[ag][0] || 0)
                        }
                    }
                    if (S && ad.type == "Native") {
                        M.save();
                        M.beginPath();
                        M.fillStyle = M.strokeStyle = ad.color;
                        M.font = ad.style + " " + ad.size + "px " + ad.family;
                        M.textAlign = "center";
                        M.textBaseline = "middle";
                        if (N(V.name, ac, ab, V)) {
                            M.fillText(W, aa, Z - K - X.labelOffset - ad.size / 2, w)
                        }
                        if (ah(V.name, ac, ab, V)) {
                            M.fillText(V.name, aa, Z + ad.size / 2 + X.labelOffset)
                        }
                        M.restore()
                    }
                }
            },
            contains: function(C, E) {
                var J = C.pos.getc(true),
                z = C.getData("width"),
                N = C.getData("height"),
                M = this.getAlignedPos(J, z, N),
                L = M.x,
                K = M.y,
                O = C.getData("dimArray"),
                w = E.x - L;
                if (E.x < L || E.x > L + z || E.y > K || E.y < K - N) {
                    return false
                }
                for (var F = 0,
                D = O.length,
                I = K,
                A = K; F < D; F++) {
                    var B = O[F];
                    I -= B[0];
                    A -= B[1];
                    var G = I + (A - I) * w / z;
                    if (E.y >= G) {
                        var H = +(w > z / 2);
                        return {
                            name: C.getData("stringArray")[F],
                            color: C.getData("colorArray")[F],
                            value: C.getData("valueArray")[F][H],
                            index: H
                        }
                    }
                }
                return false
            }
        }
    });
    $jit.AreaChart = new q({
        st: null,
        colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
        selected: {},
        busy: false,
        initialize: function(y) {
            this.controller = this.config = c.merge(n("Canvas", "Margin", "Label", "AreaChart"), {
                Label: {
                    type: "Native"
                }
            },
            y);
            var z = this.config.showLabels,
            x = c.type(z),
            A = this.config.showAggregates,
            w = c.type(A);
            this.config.showLabels = x == "function" ? z: c.lambda(z);
            this.config.showAggregates = w == "function" ? A: c.lambda(A);
            this.initializeViz()
        },
        initializeViz: function() {
            var y = this.config,
            B = this,
            w = y.type.split(":")[0],
            A = {};
            var x = new $jit.ST({
                injectInto: y.injectInto,
                orientation: "bottom",
                levelDistance: 0,
                siblingOffset: 0,
                subtreeOffset: 0,
                withLabels: y.Label.type != "Native",
                useCanvas: y.useCanvas,
                Label: {
                    type: y.Label.type
                },
                Node: {
                    overridable: true,
                    type: "areachart-" + w,
                    align: "left",
                    width: 1,
                    height: 1
                },
                Edge: {
                    type: "none"
                },
                Tips: {
                    enable: y.Tips.enable,
                    type: "Native",
                    force: true,
                    onShow: function(G, F, D) {
                        var E = D;
                        y.Tips.onShow(G, E, F)
                    }
                },
                Events: {
                    enable: true,
                    type: "Native",
                    onClick: function(F, G, D) {
                        if (!y.filterOnClick && !y.Events.enable) {
                            return
                        }
                        var E = G.getContains();
                        if (E) {
                            y.filterOnClick && B.filter(E.name)
                        }
                        y.Events.enable && y.Events.onClick(E, G, D)
                    },
                    onRightClick: function(E, F, D) {
                        if (!y.restoreOnRightClick) {
                            return
                        }
                        B.restore()
                    },
                    onMouseMove: function(F, G, D) {
                        if (!y.selectOnHover) {
                            return
                        }
                        if (F) {
                            var E = G.getContains();
                            B.select(F.id, E.name, E.index)
                        } else {
                            B.select(false, false, false)
                        }
                    }
                },
                onCreateLabel: function(J, G) {
                    var P = y.Label,
                    O = G.getData("valueArray"),
                    H = c.reduce(O,
                    function(Q, R) {
                        return Q + R[0]
                    },
                    0),
                    M = c.reduce(O,
                    function(Q, R) {
                        return Q + R[1]
                    },
                    0);
                    if (G.getData("prev")) {
                        var L = {
                            wrapper: document.createElement("div"),
                            aggregate: document.createElement("div"),
                            label: document.createElement("div")
                        };
                        var D = L.wrapper,
                        N = L.label,
                        E = L.aggregate,
                        F = D.style,
                        K = N.style,
                        I = E.style;
                        A[G.id] = L;
                        D.appendChild(N);
                        D.appendChild(E);
                        if (!y.showLabels(G.name, H, M, G)) {
                            N.style.display = "none"
                        }
                        if (!y.showAggregates(G.name, H, M, G)) {
                            E.style.display = "none"
                        }
                        F.position = "relative";
                        F.overflow = "visible";
                        F.fontSize = P.size + "px";
                        F.fontFamily = P.family;
                        F.color = P.color;
                        F.textAlign = "center";
                        I.position = K.position = "absolute";
                        J.style.width = G.getData("width") + "px";
                        J.style.height = G.getData("height") + "px";
                        N.innerHTML = G.name;
                        J.appendChild(D)
                    }
                },
                onPlaceLabel: function(U, O) {
                    if (!O.getData("prev")) {
                        return
                    }
                    var S = A[O.id],
                    E = S.wrapper.style,
                    D = S.label.style,
                    N = S.aggregate.style,
                    L = O.getData("width"),
                    J = O.getData("height"),
                    I = O.getData("dimArray"),
                    F = O.getData("valueArray"),
                    K = c.reduce(F,
                    function(V, W) {
                        return V + W[0]
                    },
                    0),
                    G = c.reduce(F,
                    function(V, W) {
                        return V + W[1]
                    },
                    0),
                    H = parseInt(E.fontSize, 10),
                    M = U.style;
                    if (I && F) {
                        if (y.showLabels(O.name, K, G, O)) {
                            D.display = ""
                        } else {
                            D.display = "none"
                        }
                        if (y.showAggregates(O.name, K, G, O)) {
                            N.display = ""
                        } else {
                            N.display = "none"
                        }
                        E.width = N.width = D.width = U.style.width = L + "px";
                        N.left = D.left = -L / 2 + "px";
                        for (var R = 0,
                        P = F.length,
                        Q = 0,
                        T = 0; R < P; R++) {
                            if (I[R][0] > 0) {
                                Q += F[R][0];
                                T += I[R][0]
                            }
                        }
                        N.top = ( - H - y.labelOffset) + "px";
                        D.top = (y.labelOffset + T) + "px";
                        U.style.top = parseInt(U.style.top, 10) - T + "px";
                        U.style.height = E.height = T + "px";
                        S.aggregate.innerHTML = Q
                    }
                }
            });
            var z = x.canvas.getSize(),
            C = y.Margin;
            x.config.offsetY = -z.height / 2 + C.bottom + (y.showLabels && (y.labelOffset + y.Label.size));
            x.config.offsetX = (C.right - C.left) / 2;
            this.st = x;
            this.canvas = this.st.canvas
        },
        loadJSON: function(N) {
            var K = c.time(),
            B = [],
            G = this.st,
            Q = c.splat(N.label),
            J = c.splat(N.color || this.colors),
            O = this.config,
            x = !!O.type.split(":")[1],
            z = O.animate;
            for (var L = 0,
            y = N.values,
            I = y.length; L < I - 1; L++) {
                var P = y[L],
                E = y[L - 1],
                F = y[L + 1];
                var M = c.splat(y[L].values),
                w = c.splat(y[L + 1].values);
                var A = c.zip(M, w);
                var D = 0,
                C = 0;
                B.push({
                    id: K + P.label,
                    name: P.label,
                    data: {
                        value: A,
                        "$valueArray": A,
                        "$colorArray": J,
                        "$stringArray": Q,
                        "$next": F.label,
                        "$prev": E ? E.label: false,
                        "$config": O,
                        "$gradient": x
                    },
                    children: []
                })
            }
            var H = {
                id: K + "$root",
                name: "",
                data: {
                    "$type": "none",
                    "$width": 1,
                    "$height": 1
                },
                children: B
            };
            G.loadJSON(H);
            this.normalizeDims();
            G.compute();
            G.select(G.root);
            if (z) {
                G.fx.animate({
                    modes: ["node-property:height:dimArray"],
                    duration: 1500
                })
            }
        },
        updateJSON: function(z, C) {
            if (this.busy) {
                return
            }
            this.busy = true;
            var y = this.st,
            B = y.graph,
            D = z.label && c.splat(z.label),
            x = z.values,
            w = this.config.animate,
            A = this;
            c.each(x,
            function(F) {
                var L = B.getByName(F.label);
                if (L) {
                    F.values = c.splat(F.values);
                    var G = L.getData("stringArray"),
                    K = L.getData("valueArray");
                    c.each(K,
                    function(M, N) {
                        M[0] = F.values[N];
                        if (D) {
                            G[N] = D[N]
                        }
                    });
                    L.setData("valueArray", K);
                    var I = L.getData("prev"),
                    H = L.getData("next"),
                    E = B.getByName(H);
                    if (I) {
                        var J = B.getByName(I);
                        if (J) {
                            var K = J.getData("valueArray");
                            c.each(K,
                            function(M, N) {
                                M[1] = F.values[N]
                            })
                        }
                    }
                    if (!E) {
                        var K = L.getData("valueArray");
                        c.each(K,
                        function(M, N) {
                            M[1] = F.values[N]
                        })
                    }
                }
            });
            this.normalizeDims();
            y.compute();
            y.select(y.root);
            if (w) {
                y.fx.animate({
                    modes: ["node-property:height:dimArray"],
                    duration: 1500,
                    onComplete: function() {
                        A.busy = false;
                        C && C.onComplete()
                    }
                })
            }
        },
        filter: function() {
            if (this.busy) {
                return
            }
            this.busy = true;
            if (this.config.Tips.enable) {
                this.st.tips.hide()
            }
            this.select(false, false, false);
            var x = Array.prototype.slice.call(arguments);
            var w = this.st.graph.getNode(this.st.root);
            var y = this;
            w.eachAdjacency(function(z) {
                var C = z.nodeTo,
                B = C.getData("dimArray"),
                A = C.getData("stringArray");
                C.setData("dimArray", c.map(B,
                function(E, D) {
                    return (c.indexOf(x, A[D]) > -1) ? E: [0, 0]
                }), "end")
            });
            this.st.fx.animate({
                modes: ["node-property:dimArray"],
                duration: 1500,
                onComplete: function() {
                    y.busy = false
                }
            })
        },
        restore: function() {
            if (this.busy) {
                return
            }
            this.busy = true;
            if (this.config.Tips.enable) {
                this.st.tips.hide()
            }
            this.select(false, false, false);
            this.normalizeDims();
            var w = this;
            this.st.fx.animate({
                modes: ["node-property:height:dimArray"],
                duration: 1500,
                onComplete: function() {
                    w.busy = false
                }
            })
        },
        select: function(B, x, w) {
            if (!this.config.selectOnHover) {
                return
            }
            var y = this.selected;
            if (y.id != B || y.name != x || y.index != w) {
                y.id = B;
                y.name = x;
                y.index = w;
                this.st.graph.eachNode(function(C) {
                    C.setData("border", false)
                });
                if (B) {
                    var A = this.st.graph.getNode(B);
                    A.setData("border", y);
                    var z = w === 0 ? "prev": "next";
                    z = A.getData(z);
                    if (z) {
                        A = this.st.graph.getByName(z);
                        if (A) {
                            A.setData("border", {
                                name: x,
                                index: 1 - w
                            })
                        }
                    }
                }
                this.st.plot()
            }
        },
        getLegend: function() {
            var y = {};
            var z;
            this.st.graph.getNode(this.st.root).eachAdjacency(function(A) {
                z = A.nodeTo
            });
            var x = z.getData("colorArray"),
            w = x.length;
            c.each(z.getData("stringArray"),
            function(B, A) {
                y[B] = x[A % w]
            });
            return y
        },
        getMaxValue: function() {
            var w = 0;
            this.st.graph.eachNode(function(B) {
                var y = B.getData("valueArray"),
                x = 0,
                A = 0;
                c.each(y,
                function(C) {
                    x += +C[0];
                    A += +C[1]
                });
                var z = A > x ? A: x;
                w = w > z ? w: z
            });
            return w
        },
        normalizeDims: function() {
            var C = this.st.graph.getNode(this.st.root),
            z = 0;
            C.eachAdjacency(function() {
                z++
            });
            var B = this.getMaxValue() || 1,
            F = this.st.canvas.getSize(),
            y = this.config,
            A = y.Margin,
            D = y.labelOffset + y.Label.size,
            w = (F.width - (A.left + A.right)) / z,
            x = y.animate,
            E = F.height - (A.top + A.bottom) - (y.showAggregates && D) - (y.showLabels && D);
            this.st.graph.eachNode(function(L) {
                var I = 0,
                K = 0,
                G = [];
                c.each(L.getData("valueArray"),
                function(M) {
                    I += +M[0];
                    K += +M[1];
                    G.push([0, 0])
                });
                var J = K > I ? K: I;
                L.setData("width", w);
                if (x) {
                    L.setData("height", J * E / B, "end");
                    L.setData("dimArray", c.map(L.getData("valueArray"),
                    function(M) {
                        return [M[0] * E / B, M[1] * E / B]
                    }), "end");
                    var H = L.getData("dimArray");
                    if (!H) {
                        L.setData("dimArray", G)
                    }
                } else {
                    L.setData("height", J * E / B);
                    L.setData("dimArray", c.map(L.getData("valueArray"),
                    function(M) {
                        return [M[0] * E / B, M[1] * E / B]
                    }))
                }
            })
        }
    });
    n.BarChart = {
        $extend: true,
        animate: true,
        type: "stacked",
        labelOffset: 3,
        barsOffset: 0,
        hoveredColor: "#9fd4ff",
        orientation: "horizontal",
        showAggregates: true,
        showLabels: true,
        Tips: {
            enable: false,
            onShow: c.empty,
            onHide: c.empty
        },
        Events: {
            enable: false,
            onClick: c.empty
        }
    };
    $jit.ST.Plot.NodeTypes.implement({
        "barchart-stacked": {
            render: function(Q, C) {
                var H = Q.pos.getc(true),
                P = Q.getData("width"),
                N = Q.getData("height"),
                L = this.getAlignedPos(H, P, N),
                K = L.x,
                J = L.y,
                M = Q.getData("dimArray"),
                F = Q.getData("valueArray"),
                E = Q.getData("colorArray"),
                B = E.length,
                X = Q.getData("stringArray");
                var S = C.getCtx(),
                w = {},
                T = Q.getData("border"),
                z = Q.getData("gradient"),
                Z = Q.getData("config"),
                A = Z.orientation == "horizontal",
                D = Z.showAggregates,
                O = Z.showLabels,
                I = Z.Label;
                if (E && M && X) {
                    for (var W = 0,
                    R = M.length,
                    V = 0,
                    G = 0; W < R; W++) {
                        S.fillStyle = S.strokeStyle = E[W % B];
                        if (z) {
                            var Y;
                            if (A) {
                                Y = S.createLinearGradient(K + V + M[W] / 2, J, K + V + M[W] / 2, J + N)
                            } else {
                                Y = S.createLinearGradient(K, J - V - M[W] / 2, K + P, J - V - M[W] / 2)
                            }
                            var U = c.rgbToHex(c.map(c.hexToRgb(E[W % B].slice(1)),
                            function(x) {
                                return (x * 0.5) >> 0
                            }));
                            Y.addColorStop(0, U);
                            Y.addColorStop(0.5, E[W % B]);
                            Y.addColorStop(1, U);
                            S.fillStyle = Y
                        }
                        if (A) {
                            S.fillRect(K + V, J, M[W], N)
                        } else {
                            S.fillRect(K, J - V - M[W], P, M[W])
                        }
                        if (T && T.name == X[W]) {
                            w.acum = V;
                            w.dimValue = M[W]
                        }
                        V += (M[W] || 0);
                        G += (F[W] || 0)
                    }
                    if (T) {
                        S.save();
                        S.lineWidth = 2;
                        S.strokeStyle = T.color;
                        if (A) {
                            S.strokeRect(K + w.acum + 1, J + 1, w.dimValue - 2, N - 2)
                        } else {
                            S.strokeRect(K + 1, J - w.acum - w.dimValue + 1, P - 2, w.dimValue - 2)
                        }
                        S.restore()
                    }
                    if (I.type == "Native") {
                        S.save();
                        S.fillStyle = S.strokeStyle = I.color;
                        S.font = I.style + " " + I.size + "px " + I.family;
                        S.textBaseline = "middle";
                        if (D(Q.name, G)) {
                            if (A) {
                                S.textAlign = "right";
                                S.fillText(G, K + V - Z.labelOffset, J + N / 2)
                            } else {
                                S.textAlign = "center";
                                S.fillText(G, K + P / 2, J - N - I.size / 2 - Z.labelOffset)
                            }
                        }
                        if (O(Q.name, G, Q)) {
                            if (A) {
                                S.textAlign = "center";
                                S.translate(K - Z.labelOffset - I.size / 2, J + N / 2);
                                S.rotate(Math.PI / 2);
                                S.fillText(Q.name, 0, 0)
                            } else {
                                S.textAlign = "center";
                                S.fillText(Q.name, K + P / 2, J + I.size / 2 + Z.labelOffset)
                            }
                        }
                        S.restore()
                    }
                }
            },
            contains: function(D, F) {
                var I = D.pos.getc(true),
                A = D.getData("width"),
                N = D.getData("height"),
                M = this.getAlignedPos(I, A, N),
                L = M.x,
                J = M.y,
                O = D.getData("dimArray"),
                B = D.getData("config"),
                z = F.x - L,
                w = B.orientation == "horizontal";
                if (w) {
                    if (F.x < L || F.x > L + A || F.y > J + N || F.y < J) {
                        return false
                    }
                } else {
                    if (F.x < L || F.x > L + A || F.y > J || F.y < J - N) {
                        return false
                    }
                }
                for (var G = 0,
                E = O.length,
                K = (w ? L: J); G < E; G++) {
                    var C = O[G];
                    if (w) {
                        K += C;
                        var H = K;
                        if (F.x <= H) {
                            return {
                                name: D.getData("stringArray")[G],
                                color: D.getData("colorArray")[G],
                                value: D.getData("valueArray")[G],
                                label: D.name
                            }
                        }
                    } else {
                        K -= C;
                        var H = K;
                        if (F.y >= H) {
                            return {
                                name: D.getData("stringArray")[G],
                                color: D.getData("colorArray")[G],
                                value: D.getData("valueArray")[G],
                                label: D.name
                            }
                        }
                    }
                }
                return false
            }
        },
        "barchart-grouped": {
            render: function(R, C) {
                var I = R.pos.getc(true),
                Q = R.getData("width"),
                O = R.getData("height"),
                M = this.getAlignedPos(I, Q, O),
                L = M.x,
                K = M.y,
                N = R.getData("dimArray"),
                G = R.getData("valueArray"),
                X = G.length,
                F = R.getData("colorArray"),
                B = F.length,
                Z = R.getData("stringArray");
                var T = C.getCtx(),
                w = {},
                U = R.getData("border"),
                z = R.getData("gradient"),
                ab = R.getData("config"),
                A = ab.orientation == "horizontal",
                E = ab.showAggregates,
                P = ab.showLabels,
                J = ab.Label,
                D = (A ? O: Q) / X;
                if (F && N && Z) {
                    for (var Y = 0,
                    S = X,
                    W = 0,
                    H = 0; Y < S; Y++) {
                        T.fillStyle = T.strokeStyle = F[Y % B];
                        if (z) {
                            var aa;
                            if (A) {
                                aa = T.createLinearGradient(L + N[Y] / 2, K + D * Y, L + N[Y] / 2, K + D * (Y + 1))
                            } else {
                                aa = T.createLinearGradient(L + D * Y, K - N[Y] / 2, L + D * (Y + 1), K - N[Y] / 2)
                            }
                            var V = c.rgbToHex(c.map(c.hexToRgb(F[Y % B].slice(1)),
                            function(x) {
                                return (x * 0.5) >> 0
                            }));
                            aa.addColorStop(0, V);
                            aa.addColorStop(0.5, F[Y % B]);
                            aa.addColorStop(1, V);
                            T.fillStyle = aa
                        }
                        if (A) {
                            T.fillRect(L, K + D * Y, N[Y], D)
                        } else {
                            T.fillRect(L + D * Y, K - N[Y], D, N[Y])
                        }
                        if (U && U.name == Z[Y]) {
                            w.acum = D * Y;
                            w.dimValue = N[Y]
                        }
                        W += (N[Y] || 0);
                        H += (G[Y] || 0)
                    }
                    if (U) {
                        T.save();
                        T.lineWidth = 2;
                        T.strokeStyle = U.color;
                        if (A) {
                            T.strokeRect(L + 1, K + w.acum + 1, w.dimValue - 2, D - 2)
                        } else {
                            T.strokeRect(L + w.acum + 1, K - w.dimValue + 1, D - 2, w.dimValue - 2)
                        }
                        T.restore()
                    }
                    if (J.type == "Native") {
                        T.save();
                        T.fillStyle = T.strokeStyle = J.color;
                        T.font = J.style + " " + J.size + "px " + J.family;
                        T.textBaseline = "middle";
                        if (E(R.name, H)) {
                            if (A) {
                                T.textAlign = "right";
                                T.fillText(H, L + Math.max.apply(null, N) - ab.labelOffset, K + O / 2)
                            } else {
                                T.textAlign = "center";
                                T.fillText(H, L + Q / 2, K - Math.max.apply(null, N) - J.size / 2 - ab.labelOffset)
                            }
                        }
                        if (P(R.name, H, R)) {
                            if (A) {
                                T.textAlign = "center";
                                T.translate(L - ab.labelOffset - J.size / 2, K + O / 2);
                                T.rotate(Math.PI / 2);
                                T.fillText(R.name, 0, 0)
                            } else {
                                T.textAlign = "center";
                                T.fillText(R.name, L + Q / 2, K + J.size / 2 + ab.labelOffset)
                            }
                        }
                        T.restore()
                    }
                }
            },
            contains: function(J, F) {
                var B = J.pos.getc(true),
                I = J.getData("width"),
                H = J.getData("height"),
                E = this.getAlignedPos(B, I, H),
                D = E.x,
                C = E.y,
                G = J.getData("dimArray"),
                M = G.length,
                P = J.getData("config"),
                A = F.x - D,
                w = P.orientation == "horizontal",
                z = (w ? H: I) / M;
                if (w) {
                    if (F.x < D || F.x > D + I || F.y > C + H || F.y < C) {
                        return false
                    }
                } else {
                    if (F.x < D || F.x > D + I || F.y > C || F.y < C - H) {
                        return false
                    }
                }
                for (var L = 0,
                K = G.length; L < K; L++) {
                    var O = G[L];
                    if (w) {
                        var N = C + z * L;
                        if (F.x <= D + O && F.y >= N && F.y <= N + z) {
                            return {
                                name: J.getData("stringArray")[L],
                                color: J.getData("colorArray")[L],
                                value: J.getData("valueArray")[L],
                                label: J.name
                            }
                        }
                    } else {
                        var N = D + z * L;
                        if (F.x >= N && F.x <= N + z && F.y >= C - O) {
                            return {
                                name: J.getData("stringArray")[L],
                                color: J.getData("colorArray")[L],
                                value: J.getData("valueArray")[L],
                                label: J.name
                            }
                        }
                    }
                }
                return false
            }
        }
    });
    $jit.BarChart = new q({
        st: null,
        colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
        selected: {},
        busy: false,
        initialize: function(y) {
            this.controller = this.config = c.merge(n("Canvas", "Margin", "Label", "BarChart"), {
                Label: {
                    type: "Native"
                }
            },
            y);
            var z = this.config.showLabels,
            x = c.type(z),
            A = this.config.showAggregates,
            w = c.type(A);
            this.config.showLabels = x == "function" ? z: c.lambda(z);
            this.config.showAggregates = w == "function" ? A: c.lambda(A);
            this.initializeViz()
        },
        initializeViz: function() {
            var y = this.config,
            B = this;
            var w = y.type.split(":")[0],
            D = y.orientation == "horizontal",
            A = {};
            var x = new $jit.ST({
                injectInto: y.injectInto,
                orientation: D ? "left": "bottom",
                levelDistance: 0,
                siblingOffset: y.barsOffset,
                subtreeOffset: 0,
                withLabels: y.Label.type != "Native",
                useCanvas: y.useCanvas,
                Label: {
                    type: y.Label.type
                },
                Node: {
                    overridable: true,
                    type: "barchart-" + w,
                    align: "left",
                    width: 1,
                    height: 1
                },
                Edge: {
                    type: "none"
                },
                Tips: {
                    enable: y.Tips.enable,
                    type: "Native",
                    force: true,
                    onShow: function(H, G, E) {
                        var F = E;
                        y.Tips.onShow(H, F, G)
                    }
                },
                Events: {
                    enable: true,
                    type: "Native",
                    onClick: function(G, H, E) {
                        if (!y.Events.enable) {
                            return
                        }
                        var F = H.getContains();
                        y.Events.onClick(F, H, E)
                    },
                    onMouseMove: function(G, H, E) {
                        if (!y.hoveredColor) {
                            return
                        }
                        if (G) {
                            var F = H.getContains();
                            B.select(G.id, F.name, F.index)
                        } else {
                            B.select(false, false, false)
                        }
                    }
                },
                onCreateLabel: function(J, H) {
                    var P = y.Label,
                    N = H.getData("valueArray"),
                    M = c.reduce(N,
                    function(Q, R) {
                        return Q + R
                    },
                    0);
                    var L = {
                        wrapper: document.createElement("div"),
                        aggregate: document.createElement("div"),
                        label: document.createElement("div")
                    };
                    var E = L.wrapper,
                    O = L.label,
                    F = L.aggregate,
                    G = E.style,
                    K = O.style,
                    I = F.style;
                    A[H.id] = L;
                    E.appendChild(O);
                    E.appendChild(F);
                    if (!y.showLabels(H.name, M, H)) {
                        K.display = "none"
                    }
                    if (!y.showAggregates(H.name, M, H)) {
                        I.display = "none"
                    }
                    G.position = "relative";
                    G.overflow = "visible";
                    G.fontSize = P.size + "px";
                    G.fontFamily = P.family;
                    G.color = P.color;
                    G.textAlign = "center";
                    I.position = K.position = "absolute";
                    J.style.width = H.getData("width") + "px";
                    J.style.height = H.getData("height") + "px";
                    I.left = K.left = "0px";
                    O.innerHTML = H.name;
                    J.appendChild(E)
                },
                onPlaceLabel: function(L, H) {
                    if (!A[H.id]) {
                        return
                    }
                    var N = A[H.id],
                    I = N.wrapper.style,
                    P = N.label.style,
                    M = N.aggregate.style,
                    Q = y.type.split(":")[0] == "grouped",
                    E = y.orientation == "horizontal",
                    T = H.getData("dimArray"),
                    U = H.getData("valueArray"),
                    F = (Q && E) ? Math.max.apply(null, T) : H.getData("width"),
                    S = (Q && !E) ? Math.max.apply(null, T) : H.getData("height"),
                    G = parseInt(I.fontSize, 10),
                    O = L.style;
                    if (T && U) {
                        I.width = M.width = P.width = L.style.width = F + "px";
                        for (var K = 0,
                        J = U.length,
                        R = 0; K < J; K++) {
                            if (T[K] > 0) {
                                R += U[K]
                            }
                        }
                        if (y.showLabels(H.name, R, H)) {
                            P.display = ""
                        } else {
                            P.display = "none"
                        }
                        if (y.showAggregates(H.name, R, H)) {
                            M.display = ""
                        } else {
                            M.display = "none"
                        }
                        if (y.orientation == "horizontal") {
                            M.textAlign = "right";
                            P.textAlign = "left";
                            P.textIndex = M.textIndent = y.labelOffset + "px";
                            M.top = P.top = (S - G) / 2 + "px";
                            L.style.height = I.height = S + "px"
                        } else {
                            M.top = ( - G - y.labelOffset) + "px";
                            P.top = (y.labelOffset + S) + "px";
                            L.style.top = parseInt(L.style.top, 10) - S + "px";
                            L.style.height = I.height = S + "px"
                        }
                        N.aggregate.innerHTML = R
                    }
                }
            });
            var z = x.canvas.getSize(),
            C = y.Margin;
            if (D) {
                x.config.offsetX = z.width / 2 - C.left - (y.showLabels && (y.labelOffset + y.Label.size));
                x.config.offsetY = (C.bottom - C.top) / 2
            } else {
                x.config.offsetY = -z.height / 2 + C.bottom + (y.showLabels && (y.labelOffset + y.Label.size));
                x.config.offsetX = (C.right - C.left) / 2
            }
            this.st = x;
            this.canvas = this.st.canvas
        },
        loadJSON: function(K) {
            if (this.busy) {
                return
            }
            this.busy = true;
            var I = c.time(),
            C = [],
            D = this.st,
            N = c.splat(K.label),
            H = c.splat(K.color || this.colors),
            L = this.config,
            w = !!L.type.split(":")[1],
            z = L.animate,
            y = L.orientation == "horizontal",
            A = this;
            for (var J = 0,
            x = K.values,
            F = x.length; J < F; J++) {
                var M = x[J];
                var B = c.splat(x[J].values);
                var G = 0;
                C.push({
                    id: I + M.label,
                    name: M.label,
                    data: {
                        value: B,
                        "$valueArray": B,
                        "$colorArray": H,
                        "$stringArray": N,
                        "$gradient": w,
                        "$config": L
                    },
                    children: []
                })
            }
            var E = {
                id: I + "$root",
                name: "",
                data: {
                    "$type": "none",
                    "$width": 1,
                    "$height": 1
                },
                children: C
            };
            D.loadJSON(E);
            this.normalizeDims();
            D.compute();
            D.select(D.root);
            if (z) {
                if (y) {
                    D.fx.animate({
                        modes: ["node-property:width:dimArray"],
                        duration: 1500,
                        onComplete: function() {
                            A.busy = false
                        }
                    })
                } else {
                    D.fx.animate({
                        modes: ["node-property:height:dimArray"],
                        duration: 1500,
                        onComplete: function() {
                            A.busy = false
                        }
                    })
                }
            } else {
                this.busy = false
            }
        },
        updateJSON: function(z, C) {
            if (this.busy) {
                return
            }
            this.busy = true;
            var y = this.st;
            var B = y.graph;
            var x = z.values;
            var w = this.config.animate;
            var A = this;
            var D = this.config.orientation == "horizontal";
            c.each(x,
            function(E) {
                var F = B.getByName(E.label);
                if (F) {
                    F.setData("valueArray", c.splat(E.values));
                    if (z.label) {
                        F.setData("stringArray", c.splat(z.label))
                    }
                }
            });
            this.normalizeDims();
            y.compute();
            y.select(y.root);
            if (w) {
                if (D) {
                    y.fx.animate({
                        modes: ["node-property:width:dimArray"],
                        duration: 1500,
                        onComplete: function() {
                            A.busy = false;
                            C && C.onComplete()
                        }
                    })
                } else {
                    y.fx.animate({
                        modes: ["node-property:height:dimArray"],
                        duration: 1500,
                        onComplete: function() {
                            A.busy = false;
                            C && C.onComplete()
                        }
                    })
                }
            }
        },
        select: function(y, w) {
            if (!this.config.hoveredColor) {
                return
            }
            var x = this.selected;
            if (x.id != y || x.name != w) {
                x.id = y;
                x.name = w;
                x.color = this.config.hoveredColor;
                this.st.graph.eachNode(function(z) {
                    if (y == z.id) {
                        z.setData("border", x)
                    } else {
                        z.setData("border", false)
                    }
                });
                this.st.plot()
            }
        },
        getLegend: function() {
            var y = {};
            var z;
            this.st.graph.getNode(this.st.root).eachAdjacency(function(A) {
                z = A.nodeTo
            });
            var x = z.getData("colorArray"),
            w = x.length;
            c.each(z.getData("stringArray"),
            function(B, A) {
                y[B] = x[A % w]
            });
            return y
        },
        getMaxValue: function() {
            var x = 0,
            w = this.config.type.split(":")[0] == "stacked";
            this.st.graph.eachNode(function(A) {
                var y = A.getData("valueArray"),
                z = 0;
                if (!y) {
                    return
                }
                if (w) {
                    c.each(y,
                    function(B) {
                        z += +B
                    })
                } else {
                    z = Math.max.apply(null, y)
                }
                x = x > z ? x: z
            });
            return x
        },
        setBarType: function(w) {
            this.config.type = w;
            this.st.config.Node.type = "barchart-" + w.split(":")[0]
        },
        normalizeDims: function() {
            var G = this.st.graph.getNode(this.st.root),
            B = 0;
            G.eachAdjacency(function() {
                B++
            });
            var D = this.getMaxValue() || 1,
            J = this.st.canvas.getSize(),
            z = this.config,
            C = z.Margin,
            H = C.left + C.right,
            A = C.top + C.bottom,
            x = z.orientation == "horizontal",
            w = (J[x ? "height": "width"] - (x ? A: H) - (B - 1) * z.barsOffset) / B,
            y = z.animate,
            I = J[x ? "width": "height"] - (x ? H: A) - (!x && z.showAggregates && (z.Label.size + z.labelOffset)) - (z.showLabels && (z.Label.size + z.labelOffset)),
            F = x ? "height": "width",
            E = x ? "width": "height";
            this.st.graph.eachNode(function(N) {
                var M = 0,
                K = [];
                c.each(N.getData("valueArray"),
                function(O) {
                    M += +O;
                    K.push(0)
                });
                N.setData(F, w);
                if (y) {
                    N.setData(E, M * I / D, "end");
                    N.setData("dimArray", c.map(N.getData("valueArray"),
                    function(O) {
                        return O * I / D
                    }), "end");
                    var L = N.getData("dimArray");
                    if (!L) {
                        N.setData("dimArray", K)
                    }
                } else {
                    N.setData(E, M * I / D);
                    N.setData("dimArray", c.map(N.getData("valueArray"),
                    function(O) {
                        return O * I / D
                    }))
                }
            })
        }
    });
    n.PieChart = {
        $extend: true,
        animate: true,
        offset: 25,
        sliceOffset: 0,
        labelOffset: 3,
        type: "stacked",
        hoveredColor: "#9fd4ff",
        Events: {
            enable: false,
            onClick: c.empty
        },
        Tips: {
            enable: false,
            onShow: c.empty,
            onHide: c.empty
        },
        showLabels: true,
        resizeLabels: false,
        updateHeights: false
    };
    g.Radial = new q({
        compute: function(x) {
            var y = c.splat(x || ["current", "start", "end"]);
            f.compute(this.graph, y, this.config);
            this.graph.computeLevels(this.root, 0, "ignore");
            var w = this.createLevelDistanceFunc();
            this.computeAngularWidths(y);
            this.computePositions(y, w)
        },
        computePositions: function(D, A) {
            var F = D;
            var E = this.graph;
            var B = E.getNode(this.root);
            var C = this.parent;
            var w = this.config;
            for (var y = 0,
            x = F.length; y < x; y++) {
                var z = F[y];
                B.setPos(k(0, 0), z);
                B.setData("span", Math.PI * 2, z)
            }
            B.angleSpan = {
                begin: 0,
                end: 2 * Math.PI
            };
            E.eachBFS(this.root,
            function(K) {
                var Q = K.angleSpan.end - K.angleSpan.begin;
                var S = K.angleSpan.begin;
                var R = A(K);
                var T = 0,
                G = [],
                J = {};
                K.eachSubnode(function(W) {
                    T += W._treeAngularWidth;
                    for (var X = 0,
                    V = F.length; X < V; X++) {
                        var Z = F[X],
                        Y = W.getData("dim", Z);
                        J[Z] = (Z in J) ? (Y > J[Z] ? Y: J[Z]) : Y
                    }
                    G.push(W)
                },
                "ignore");
                if (C && C.id == K.id && G.length > 0 && G[0].dist) {
                    G.sort(function(W, V) {
                        return (W.dist >= V.dist) - (W.dist <= V.dist)
                    })
                }
                for (var M = 0,
                O = G.length; M < O; M++) {
                    var I = G[M];
                    if (!I._flag) {
                        var U = I._treeAngularWidth / T * Q;
                        var H = S + U / 2;
                        for (var N = 0,
                        L = F.length; N < L; N++) {
                            var P = F[N];
                            I.setPos(k(H, R), P);
                            I.setData("span", U, P);
                            I.setData("dim-quotient", I.getData("dim", P) / J[P], P)
                        }
                        I.angleSpan = {
                            begin: S,
                            end: S + U
                        };
                        S += U
                    }
                }
            },
            "ignore")
        },
        setAngularWidthForNodes: function(w) {
            this.graph.eachBFS(this.root,
            function(z, x) {
                var y = z.getData("angularWidth", w[0]) || 5;
                z._angularWidth = y / x
            },
            "ignore")
        },
        setSubtreesAngularWidth: function() {
            var w = this;
            this.graph.eachNode(function(x) {
                w.setSubtreeAngularWidth(x)
            },
            "ignore")
        },
        setSubtreeAngularWidth: function(z) {
            var y = this,
            x = z._angularWidth,
            w = 0;
            z.eachSubnode(function(A) {
                y.setSubtreeAngularWidth(A);
                w += A._treeAngularWidth
            },
            "ignore");
            z._treeAngularWidth = Math.max(x, w)
        },
        computeAngularWidths: function(w) {
            this.setAngularWidthForNodes(w);
            this.setSubtreesAngularWidth()
        }
    });
    $jit.Sunburst = new q({
        Implements: [d, o, g.Radial],
        initialize: function(w) {
            var y = $jit.Sunburst;
            var x = {
                interpolation: "linear",
                levelDistance: 100,
                Node: {
                    type: "multipie",
                    height: 0
                },
                Edge: {
                    type: "none"
                },
                Label: {
                    textAlign: "start",
                    textBaseline: "middle"
                }
            };
            this.controller = this.config = c.merge(n("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), x, w);
            var z = this.config;
            if (z.useCanvas) {
                this.canvas = z.useCanvas;
                this.config.labelContainer = this.canvas.id + "-label"
            } else {
                if (z.background) {
                    z.background = c.merge({
                        type: "Circles"
                    },
                    z.background)
                }
                this.canvas = new l(this, z);
                this.config.labelContainer = (typeof z.injectInto == "string" ? z.injectInto: z.injectInto.id) + "-label"
            }
            this.graphOptions = {
                complex: false,
                Node: {
                    selected: false,
                    exist: true,
                    drawn: true
                }
            };
            this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
            this.labels = new y.Label[z.Label.type](this);
            this.fx = new y.Plot(this, y);
            this.op = new y.Op(this);
            this.json = null;
            this.root = null;
            this.rotated = null;
            this.busy = false;
            this.initializeExtras()
        },
        createLevelDistanceFunc: function() {
            var w = this.config.levelDistance;
            return function(x) {
                return (x._depth + 1) * w
            }
        },
        refresh: function() {
            this.compute();
            this.plot()
        },
        reposition: function() {
            this.compute("end")
        },
        rotate: function(y, z, x) {
            var w = y.getPos(x.property || "current").getp(true).theta;
            this.rotated = y;
            this.rotateAngle( - w, z, x)
        },
        rotateAngle: function(y, B, x) {
            var z = this;
            var w = c.merge(this.config, x || {},
            {
                modes: ["polar"]
            });
            var A = x.property || (B === "animate" ? "end": "current");
            if (B === "animate") {
                this.fx.animation.pause()
            }
            this.graph.eachNode(function(D) {
                var C = D.getPos(A);
                C.theta += y;
                if (C.theta < 0) {
                    C.theta += Math.PI * 2
                }
            });
            if (B == "animate") {
                this.fx.animate(w)
            } else {
                if (B == "replot") {
                    this.fx.plot();
                    this.busy = false
                }
            }
        },
        plot: function() {
            this.fx.plot()
        }
    });
    $jit.Sunburst.$extend = true; (function(w) {
        w.Op = new q({
            Implements: e.Op
        });
        w.Plot = new q({
            Implements: e.Plot
        });
        w.Label = {};
        w.Label.Native = new q({
            Implements: e.Label.Native,
            initialize: function(x) {
                this.viz = x;
                this.label = x.config.Label;
                this.config = x.config
            },
            renderLabel: function(C, E, G) {
                var N = E.getData("span");
                if (N < Math.PI / 2 && Math.tan(N) * this.config.levelDistance * E._depth < 10) {
                    return
                }
                var O = C.getCtx();
                var A = O.measureText(E.name);
                if (E.id == this.viz.root) {
                    var M = -A.width / 2,
                    K = 0,
                    L = 0;
                    var z = 0
                } else {
                    var D = 5;
                    var z = G.levelDistance - D;
                    var J = E.pos.clone();
                    J.rho += D;
                    var B = J.getp(true);
                    var H = J.getc(true);
                    var M = H.x,
                    K = H.y;
                    var F = Math.PI;
                    var I = (B.theta > F / 2 && B.theta < 3 * F / 2);
                    var L = I ? B.theta + F: B.theta;
                    if (I) {
                        M -= Math.abs(Math.cos(B.theta) * A.width);
                        K += Math.sin(B.theta) * A.width
                    } else {
                        if (E.id == this.viz.root) {
                            M -= A.width / 2
                        }
                    }
                }
                O.save();
                O.translate(M, K);
                O.rotate(L);
                O.fillText(E.name, 0, 0);
                O.restore()
            }
        });
        w.Label.SVG = new q({
            Implements: e.Label.SVG,
            initialize: function(x) {
                this.viz = x
            },
            placeLabel: function(N, C, E) {
                var J = C.pos.getc(true),
                M = this.viz,
                A = this.viz.canvas;
                var F = A.getSize();
                var B = {
                    x: Math.round(J.x + F.width / 2),
                    y: Math.round(J.y + F.height / 2)
                };
                N.setAttribute("x", B.x);
                N.setAttribute("y", B.y);
                var G = N.getBBox();
                if (G) {
                    var L = N.getAttribute("x");
                    var I = N.getAttribute("y");
                    var z = C.pos.getp(true);
                    var D = Math.PI;
                    var H = (z.theta > D / 2 && z.theta < 3 * D / 2);
                    if (H) {
                        N.setAttribute("x", L - G.width);
                        N.setAttribute("y", I - G.height)
                    } else {
                        if (C.id == M.root) {
                            N.setAttribute("x", L - G.width / 2)
                        }
                    }
                    var K = H ? z.theta + D: z.theta;
                    if (C._depth) {
                        N.setAttribute("transform", "rotate(" + K * 360 / (2 * D) + " " + L + " " + I + ")")
                    }
                }
                E.onPlaceLabel(N, C)
            }
        });
        w.Label.HTML = new q({
            Implements: e.Label.HTML,
            initialize: function(x) {
                this.viz = x
            },
            placeLabel: function(G, A, C) {
                var E = A.pos.clone(),
                y = this.viz.canvas,
                F = A.getData("height"),
                B = ((F || A._depth == 0) ? F: this.viz.config.levelDistance) / 2,
                D = y.getSize();
                E.rho += B;
                E = E.getc(true);
                var z = {
                    x: Math.round(E.x + D.width / 2),
                    y: Math.round(E.y + D.height / 2)
                };
                var x = G.style;
                x.left = z.x + "px";
                x.top = z.y + "px";
                x.display = this.fitsInCanvas(z, y) ? "": "none";
                C.onPlaceLabel(G, A)
            }
        });
        w.Plot.NodeTypes = new q({
            none: {
                render: c.empty,
                contains: c.lambda(false),
                anglecontains: function(B, D) {
                    var A = B.getData("span") / 2,
                    y = B.pos.theta;
                    var z = y - A,
                    x = y + A;
                    if (z < 0) {
                        z += Math.PI * 2
                    }
                    var C = Math.atan2(D.y, D.x);
                    if (C < 0) {
                        C += Math.PI * 2
                    }
                    if (z > x) {
                        return (C > z && C <= Math.PI * 2) || C < x
                    } else {
                        return C > z && C < x
                    }
                }
            },
            pie: {
                render: function(C, A) {
                    var G = C.getData("span") / 2,
                    z = C.pos.theta;
                    var B = z - G,
                    D = z + G;
                    var F = C.pos.getp(true);
                    var x = new b(F.rho, B);
                    var y = x.getc(true);
                    x.theta = D;
                    var E = x.getc(true);
                    var H = A.getCtx();
                    H.beginPath();
                    H.moveTo(0, 0);
                    H.lineTo(y.x, y.y);
                    H.moveTo(0, 0);
                    H.lineTo(E.x, E.y);
                    H.moveTo(0, 0);
                    H.arc(0, 0, F.rho * C.getData("dim-quotient"), B, D, false);
                    H.fill()
                },
                contains: function(z, B) {
                    if (this.nodeTypes.none.anglecontains.call(this, z, B)) {
                        var x = Math.sqrt(B.x * B.x + B.y * B.y);
                        var y = this.config.levelDistance,
                        A = z._depth;
                        return (x <= y * A)
                    }
                    return false
                }
            },
            multipie: {
                render: function(D, B) {
                    var K = D.getData("height");
                    var E = K ? K: this.config.levelDistance;
                    var J = D.getData("span") / 2,
                    A = D.pos.theta;
                    var C = A - J,
                    G = A + J;
                    var I = D.pos.getp(true);
                    var y = new b(I.rho, C);
                    var z = y.getc(true);
                    y.theta = G;
                    var H = y.getc(true);
                    y.rho += E;
                    var x = y.getc(true);
                    y.theta = C;
                    var F = y.getc(true);
                    var L = B.getCtx();
                    L.moveTo(0, 0);
                    L.beginPath();
                    L.arc(0, 0, I.rho, C, G, false);
                    L.arc(0, 0, I.rho + E, G, C, true);
                    L.moveTo(z.x, z.y);
                    L.lineTo(F.x, F.y);
                    L.moveTo(H.x, H.y);
                    L.lineTo(x.x, x.y);
                    L.fill();
                    if (D.collapsed) {
                        L.save();
                        L.lineWidth = 2;
                        L.moveTo(0, 0);
                        L.beginPath();
                        L.arc(0, 0, I.rho + E + 5, G - 0.01, C + 0.01, true);
                        L.stroke();
                        L.restore()
                    }
                },
                contains: function(A, D) {
                    if (this.nodeTypes.none.anglecontains.call(this, A, D)) {
                        var y = Math.sqrt(D.x * D.x + D.y * D.y);
                        var x = A.getData("height");
                        var B = x ? x: this.config.levelDistance;
                        var z = this.config.levelDistance,
                        C = A._depth;
                        return (y >= z * C) && (y <= (z * C + B))
                    }
                    return false
                }
            },
            "gradient-multipie": {
                render: function(A, x) {
                    var F = x.getCtx();
                    var E = A.getData("height");
                    var B = E ? E: this.config.levelDistance;
                    var y = F.createRadialGradient(0, 0, A.getPos().rho, 0, 0, A.getPos().rho + B);
                    var D = c.hexToRgb(A.getData("color")),
                    C = [];
                    c.each(D,
                    function(G) {
                        C.push(parseInt(G * 0.5, 10))
                    });
                    var z = c.rgbToHex(C);
                    y.addColorStop(0, z);
                    y.addColorStop(1, A.getData("color"));
                    F.fillStyle = y;
                    this.nodeTypes.multipie.render.call(this, A, x)
                },
                contains: function(x, y) {
                    return this.nodeTypes.multipie.contains.call(this, x, y)
                }
            },
            "gradient-pie": {
                render: function(C, z) {
                    var x = z.getCtx();
                    var D = x.createRadialGradient(0, 0, 0, 0, 0, C.getPos().rho);
                    var B = c.hexToRgb(C.getData("color")),
                    y = [];
                    c.each(B,
                    function(E) {
                        y.push(parseInt(E * 0.5, 10))
                    });
                    var A = c.rgbToHex(y);
                    D.addColorStop(1, A);
                    D.addColorStop(0, C.getData("color"));
                    x.fillStyle = D;
                    this.nodeTypes.pie.render.call(this, C, z)
                },
                contains: function(x, y) {
                    return this.nodeTypes.pie.contains.call(this, x, y)
                }
            }
        });
        w.Plot.EdgeTypes = new q({
            none: c.empty,
            line: {
                render: function(x, y) {
                    var A = x.nodeFrom.pos.getc(true),
                    z = x.nodeTo.pos.getc(true);
                    this.edgeHelper.line.render(A, z, y)
                },
                contains: function(x, A) {
                    var z = x.nodeFrom.pos.getc(true),
                    y = x.nodeTo.pos.getc(true);
                    return this.edgeHelper.line.contains(z, y, A, this.edge.epsilon)
                }
            },
            arrow: {
                render: function(y, z) {
                    var D = y.nodeFrom.pos.getc(true),
                    C = y.nodeTo.pos.getc(true),
                    B = y.getData("dim"),
                    A = y.data.$direction,
                    x = (A && A.length > 1 && A[0] != y.nodeFrom.id);
                    this.edgeHelper.arrow.render(D, C, B, x, z)
                },
                contains: function(x, A) {
                    var z = x.nodeFrom.pos.getc(true),
                    y = x.nodeTo.pos.getc(true);
                    return this.edgeHelper.arrow.contains(z, y, A, this.edge.epsilon)
                }
            },
            hyperline: {
                render: function(x, y) {
                    var B = x.nodeFrom.pos.getc(),
                    A = x.nodeTo.pos.getc(),
                    z = Math.max(B.norm(), A.norm());
                    this.edgeHelper.hyperline.render(B.$scale(1 / z), A.$scale(1 / z), z, y)
                },
                contains: c.lambda(false)
            }
        })
    })($jit.Sunburst);
    $jit.Sunburst.Plot.NodeTypes.implement({
        "piechart-stacked": {
            render: function(U, A) {
                var T = U.pos.getp(true),
                C = U.getData("dimArray"),
                S = U.getData("valueArray"),
                G = U.getData("colorArray"),
                z = G.length,
                M = U.getData("stringArray"),
                P = U.getData("span") / 2,
                K = U.pos.theta,
                F = K - P,
                J = K + P,
                R = new b;
                var N = A.getCtx(),
                L = {},
                I = U.getData("gradient"),
                D = U.getData("border"),
                Z = U.getData("config"),
                ai = Z.showLabels,
                Y = Z.resizeLabels,
                ab = Z.Label;
                var ae = Z.sliceOffset * Math.cos((F + J) / 2);
                var E = Z.sliceOffset * Math.sin((F + J) / 2);
                if (G && C && M) {
                    for (var af = 0,
                    ac = C.length,
                    w = 0,
                    X = 0; af < ac; af++) {
                        var B = C[af],
                        ag = G[af % z];
                        if (B <= 0) {
                            continue
                        }
                        N.fillStyle = N.strokeStyle = ag;
                        if (I && B) {
                            var ad = N.createRadialGradient(ae, E, w + Z.sliceOffset, ae, E, w + B + Z.sliceOffset);
                            var x = c.hexToRgb(ag),
                            W = c.map(x,
                            function(al) {
                                return (al * 0.8) >> 0
                            }),
                            y = c.rgbToHex(W);
                            ad.addColorStop(0, ag);
                            ad.addColorStop(0.5, ag);
                            ad.addColorStop(1, y);
                            N.fillStyle = ad
                        }
                        R.rho = w + Z.sliceOffset;
                        R.theta = F;
                        var ah = R.getc(true);
                        R.theta = J;
                        var O = R.getc(true);
                        R.rho += B;
                        var aj = R.getc(true);
                        R.theta = F;
                        var Q = R.getc(true);
                        N.beginPath();
                        N.arc(ae, E, w + 0.01, F, J, false);
                        N.arc(ae, E, w + B + 0.01, J, F, true);
                        N.fill();
                        if (D && D.name == M[af]) {
                            L.acum = w;
                            L.dimValue = C[af];
                            L.begin = F;
                            L.end = J
                        }
                        w += (B || 0);
                        X += (S[af] || 0)
                    }
                    if (D) {
                        N.save();
                        N.globalCompositeOperation = "source-over";
                        N.lineWidth = 2;
                        N.strokeStyle = D.color;
                        var aa = F < J ? 1 : -1;
                        N.beginPath();
                        N.arc(ae, E, L.acum + 0.01 + 1, L.begin, L.end, false);
                        N.arc(ae, E, L.acum + L.dimValue + 0.01 - 1, L.end, L.begin, true);
                        N.closePath();
                        N.stroke();
                        N.restore()
                    }
                    if (ai && ab.type == "Native") {
                        N.save();
                        N.fillStyle = N.strokeStyle = ab.color;
                        var V = Y ? U.getData("normalizedDim") : 1,
                        H = (ab.size * V) >> 0;
                        H = H < +Y ? +Y: H;
                        N.font = ab.style + " " + H + "px " + ab.family;
                        N.textBaseline = "middle";
                        N.textAlign = "center";
                        R.rho = w + Z.labelOffset + Z.sliceOffset;
                        R.theta = U.pos.theta;
                        var ak = R.getc(true);
                        N.fillText(U.name, ak.x, ak.y);
                        N.restore()
                    }
                }
            },
            contains: function(z, D) {
                if (this.nodeTypes.none.anglecontains.call(this, z, D)) {
                    var F = Math.sqrt(D.x * D.x + D.y * D.y);
                    var w = this.config.levelDistance,
                    C = z._depth;
                    var x = z.getData("config");
                    if (F <= w * C + x.sliceOffset) {
                        var G = z.getData("dimArray");
                        for (var B = 0,
                        A = G.length,
                        E = x.sliceOffset; B < A; B++) {
                            var y = G[B];
                            if (F >= E && F <= E + y) {
                                return {
                                    name: z.getData("stringArray")[B],
                                    color: z.getData("colorArray")[B],
                                    value: z.getData("valueArray")[B],
                                    label: z.name
                                }
                            }
                            E += y
                        }
                    }
                    return false
                }
                return false
            }
        }
    });
    $jit.PieChart = new q({
        sb: null,
        colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
        selected: {},
        busy: false,
        initialize: function(w) {
            this.controller = this.config = c.merge(n("Canvas", "PieChart", "Label"), {
                Label: {
                    type: "Native"
                }
            },
            w);
            this.initializeViz()
        },
        initializeViz: function() {
            var x = this.config,
            A = this;
            var w = x.type.split(":")[0];
            var B = new $jit.Sunburst({
                injectInto: x.injectInto,
                useCanvas: x.useCanvas,
                withLabels: x.Label.type != "Native",
                Label: {
                    type: x.Label.type
                },
                Node: {
                    overridable: true,
                    type: "piechart-" + w,
                    width: 1,
                    height: 1
                },
                Edge: {
                    type: "none"
                },
                Tips: {
                    enable: x.Tips.enable,
                    type: "Native",
                    force: true,
                    onShow: function(F, E, C) {
                        var D = C;
                        x.Tips.onShow(F, D, E)
                    }
                },
                Events: {
                    enable: true,
                    type: "Native",
                    onClick: function(E, F, C) {
                        if (!x.Events.enable) {
                            return
                        }
                        var D = F.getContains();
                        x.Events.onClick(D, F, C)
                    },
                    onMouseMove: function(E, F, C) {
                        if (!x.hoveredColor) {
                            return
                        }
                        if (E) {
                            var D = F.getContains();
                            A.select(E.id, D.name, D.index)
                        } else {
                            A.select(false, false, false)
                        }
                    }
                },
                onCreateLabel: function(F, E) {
                    var C = x.Label;
                    if (x.showLabels) {
                        var D = F.style;
                        D.fontSize = C.size + "px";
                        D.fontFamily = C.family;
                        D.color = C.color;
                        D.textAlign = "center";
                        F.innerHTML = E.name
                    }
                },
                onPlaceLabel: function(S, M) {
                    if (!x.showLabels) {
                        return
                    }
                    var G = M.pos.getp(true),
                    J = M.getData("dimArray"),
                    P = M.getData("span") / 2,
                    H = M.pos.theta,
                    R = H - P,
                    D = H + P,
                    U = new b;
                    var L = x.showLabels,
                    F = x.resizeLabels,
                    I = x.Label;
                    if (J) {
                        for (var Q = 0,
                        N = J.length,
                        O = 0; Q < N; Q++) {
                            O += J[Q]
                        }
                        var T = F ? M.getData("normalizedDim") : 1,
                        C = (I.size * T) >> 0;
                        C = C < +F ? +F: C;
                        S.style.fontSize = C + "px";
                        U.rho = O + x.labelOffset + x.sliceOffset;
                        U.theta = (R + D) / 2;
                        var G = U.getc(true);
                        var E = A.canvas.getSize();
                        var K = {
                            x: Math.round(G.x + E.width / 2),
                            y: Math.round(G.y + E.height / 2)
                        };
                        S.style.left = K.x + "px";
                        S.style.top = K.y + "px"
                    }
                }
            });
            var z = B.canvas.getSize(),
            y = Math.min;
            B.config.levelDistance = y(z.width, z.height) / 2 - x.offset - x.sliceOffset;
            this.sb = B;
            this.canvas = this.sb.canvas;
            this.canvas.getCtx().globalCompositeOperation = "lighter"
        },
        loadJSON: function(K) {
            var I = c.time(),
            C = [],
            w = this.sb,
            N = c.splat(K.label),
            E = N.length,
            H = c.splat(K.color || this.colors),
            z = H.length,
            L = this.config,
            x = !!L.type.split(":")[1],
            A = L.animate,
            G = E == 1;
            for (var J = 0,
            y = K.values,
            F = y.length; J < F; J++) {
                var M = y[J];
                var B = c.splat(M.values);
                C.push({
                    id: I + M.label,
                    name: M.label,
                    data: {
                        value: B,
                        "$valueArray": B,
                        "$colorArray": G ? c.splat(H[J % z]) : H,
                        "$stringArray": N,
                        "$gradient": x,
                        "$config": L,
                        "$angularWidth": c.reduce(B,
                        function(O, P) {
                            return O + P
                        })
                    },
                    children: []
                })
            }
            var D = {
                id: I + "$root",
                name: "",
                data: {
                    "$type": "none",
                    "$width": 1,
                    "$height": 1
                },
                children: C
            };
            w.loadJSON(D);
            this.normalizeDims();
            w.refresh();
            if (A) {
                w.fx.animate({
                    modes: ["node-property:dimArray"],
                    duration: 1500
                })
            }
        },
        updateJSON: function(y, B) {
            if (this.busy) {
                return
            }
            this.busy = true;
            var C = this.sb;
            var A = C.graph;
            var x = y.values;
            var w = this.config.animate;
            var z = this;
            c.each(x,
            function(D) {
                var F = A.getByName(D.label),
                E = c.splat(D.values);
                if (F) {
                    F.setData("valueArray", E);
                    F.setData("angularWidth", c.reduce(E,
                    function(G, H) {
                        return G + H
                    }));
                    if (y.label) {
                        F.setData("stringArray", c.splat(y.label))
                    }
                }
            });
            this.normalizeDims();
            if (w) {
                C.compute("end");
                C.fx.animate({
                    modes: ["node-property:dimArray:span", "linear"],
                    duration: 1500,
                    onComplete: function() {
                        z.busy = false;
                        B && B.onComplete()
                    }
                })
            } else {
                C.refresh()
            }
        },
        select: function(y, w) {
            if (!this.config.hoveredColor) {
                return
            }
            var x = this.selected;
            if (x.id != y || x.name != w) {
                x.id = y;
                x.name = w;
                x.color = this.config.hoveredColor;
                this.sb.graph.eachNode(function(z) {
                    if (y == z.id) {
                        z.setData("border", x)
                    } else {
                        z.setData("border", false)
                    }
                });
                this.sb.plot()
            }
        },
        getLegend: function() {
            var y = {};
            var z;
            this.sb.graph.getNode(this.sb.root).eachAdjacency(function(A) {
                z = A.nodeTo
            });
            var x = z.getData("colorArray"),
            w = x.length;
            c.each(z.getData("stringArray"),
            function(B, A) {
                y[B] = x[A % w]
            });
            return y
        },
        getMaxValue: function() {
            var w = 0;
            this.sb.graph.eachNode(function(z) {
                var x = z.getData("valueArray"),
                y = 0;
                c.each(x,
                function(A) {
                    y += +A
                });
                w = w > y ? w: y
            });
            return w
        },
        normalizeDims: function() {
            var x = this.sb.graph.getNode(this.sb.root),
            w = 0;
            x.eachAdjacency(function() {
                w++
            });
            var B = this.getMaxValue() || 1,
            A = this.config,
            y = A.animate,
            z = this.sb.config.levelDistance;
            this.sb.graph.eachNode(function(G) {
                var F = 0,
                C = [];
                c.each(G.getData("valueArray"),
                function(H) {
                    F += +H;
                    C.push(1)
                });
                var E = (C.length == 1) && !A.updateHeights;
                if (y) {
                    G.setData("dimArray", c.map(G.getData("valueArray"),
                    function(H) {
                        return E ? z: (H * z / B)
                    }), "end");
                    var D = G.getData("dimArray");
                    if (!D) {
                        G.setData("dimArray", C)
                    }
                } else {
                    G.setData("dimArray", c.map(G.getData("valueArray"),
                    function(H) {
                        return E ? z: (H * z / B)
                    }))
                }
                G.setData("normalizedDim", F / B)
            })
        }
    });
    g.TM = {};
    g.TM.SliceAndDice = new q({
        compute: function(B) {
            var x = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
            this.controller.onBeforeCompute(x);
            var z = this.canvas.getSize(),
            y = this.config,
            A = z.width,
            w = z.height;
            this.graph.computeLevels(this.root, 0, "ignore");
            x.getPos(B).setc( - A / 2, -w / 2);
            x.setData("width", A, B);
            x.setData("height", w + y.titleHeight, B);
            this.computePositions(x, x, this.layout.orientation, B);
            this.controller.onAfterCompute(x)
        },
        computePositions: function(F, D, P, y) {
            var M = 0;
            F.eachSubnode(function(R) {
                M += R.getData("area", y)
            });
            var Q = this.config,
            N = Q.offset,
            J = F.getData("width", y),
            H = F.getData("height", y) - Q.titleHeight,
            x = F == D ? 1 : (D.getData("area", y) / M);
            var I, G, L, B, A, E, C;
            var O = (P == "h");
            if (O) {
                P = "v";
                I = H;
                G = J * x;
                L = "height";
                B = "y";
                A = "x";
                E = Q.titleHeight;
                C = 0
            } else {
                P = "h";
                I = H * x;
                G = J;
                L = "width";
                B = "x";
                A = "y";
                E = 0;
                C = Q.titleHeight
            }
            var w = D.getPos(y);
            D.setData("width", G, y);
            D.setData("height", I, y);
            var K = 0,
            z = this;
            D.eachSubnode(function(S) {
                var R = S.getPos(y);
                R[B] = K + w[B] + E;
                R[A] = w[A] + C;
                z.computePositions(D, S, P, y);
                K += S.getData(L, y)
            })
        }
    });
    g.TM.Area = {
        compute: function(w) {
            w = w || "current";
            var C = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
            this.controller.onBeforeCompute(C);
            var y = this.config,
            F = this.canvas.getSize(),
            x = F.width,
            E = F.height,
            D = y.offset,
            z = x - D,
            B = E - D;
            this.graph.computeLevels(this.root, 0, "ignore");
            C.getPos(w).setc( - x / 2, -E / 2);
            C.setData("width", x, w);
            C.setData("height", E, w);
            var A = {
                top: -E / 2 + y.titleHeight,
                left: -x / 2,
                width: z,
                height: B - y.titleHeight
            };
            this.computePositions(C, A, w);
            this.controller.onAfterCompute(C)
        },
        computeDim: function(B, C, E, A, z, x) {
            if (B.length + C.length == 1) {
                var y = (B.length == 1) ? B: C;
                this.layoutLast(y, E, A, x);
                return
            }
            if (B.length >= 2 && C.length == 0) {
                C = [B.shift()]
            }
            if (B.length == 0) {
                if (C.length > 0) {
                    this.layoutRow(C, E, A, x)
                }
                return
            }
            var D = B[0];
            if (z(C, E) >= z([D].concat(C), E)) {
                this.computeDim(B.slice(1), C.concat([D]), E, A, z, x)
            } else {
                var F = this.layoutRow(C, E, A, x);
                this.computeDim(B, [], F.dim, F, z, x)
            }
        },
        worstAspectRatio: function(x, F) {
            if (!x || x.length == 0) {
                return Number.MAX_VALUE
            }
            var y = 0,
            G = 0,
            B = Number.MAX_VALUE;
            for (var D = 0,
            C = x.length; D < C; D++) {
                var z = x[D]._area;
                y += z;
                B = B < z ? B: z;
                G = G > z ? G: z
            }
            var E = F * F,
            A = y * y;
            return Math.max(E * G / A, A / (E * B))
        },
        avgAspectRatio: function(B, y) {
            if (!B || B.length == 0) {
                return Number.MAX_VALUE
            }
            var D = 0;
            for (var z = 0,
            x = B.length; z < x; z++) {
                var C = B[z]._area;
                var A = C / y;
                D += y > A ? y / A: A / y
            }
            return D / x
        },
        layoutLast: function(y, x, B, A) {
            var z = y[0];
            z.getPos(A).setc(B.left, B.top);
            z.setData("width", B.width, A);
            z.setData("height", B.height, A)
        }
    };
    g.TM.Squarified = new q({
        Implements: g.TM.Area,
        computePositions: function(A, D, x) {
            var z = this.config;
            if (D.width >= D.height) {
                this.layout.orientation = "h"
            } else {
                this.layout.orientation = "v"
            }
            var w = A.getSubnodes([1, 1], "ignore");
            if (w.length > 0) {
                this.processChildrenLayout(A, w, D, x);
                for (var C = 0,
                B = w.length; C < B; C++) {
                    var F = w[C];
                    var G = z.offset,
                    H = F.getData("height", x) - G - z.titleHeight,
                    y = F.getData("width", x) - G;
                    var E = F.getPos(x);
                    D = {
                        width: y,
                        height: H,
                        top: E.y + z.titleHeight,
                        left: E.x
                    };
                    this.computePositions(F, D, x)
                }
            }
        },
        processChildrenLayout: function(G, w, C, x) {
            var A = C.width * C.height;
            var B, y = w.length,
            D = 0,
            H = [];
            for (B = 0; B < y; B++) {
                H[B] = parseFloat(w[B].getData("area", x));
                D += H[B]
            }
            for (B = 0; B < y; B++) {
                w[B]._area = A * H[B] / D
            }
            var z = this.layout.horizontal() ? C.height: C.width;
            w.sort(function(J, I) {
                var K = I._area - J._area;
                return K ? K: (I.id == J.id ? 0 : (I.id < J.id ? 1 : -1))
            });
            var F = [w[0]];
            var E = w.slice(1);
            this.squarify(E, F, z, C, x)
        },
        squarify: function(y, B, x, A, z) {
            this.computeDim(y, B, x, A, this.worstAspectRatio, z)
        },
        layoutRow: function(y, x, A, z) {
            if (this.layout.horizontal()) {
                return this.layoutV(y, x, A, z)
            } else {
                return this.layoutH(y, x, A, z)
            }
        },
        layoutV: function(x, I, E, y) {
            var J = 0,
            A = function(w) {
                return w
            };
            c.each(x,
            function(w) {
                J += w._area
            });
            var z = A(J / I),
            F = 0;
            for (var C = 0,
            B = x.length; C < B; C++) {
                var D = A(x[C]._area / z);
                var G = x[C];
                G.getPos(y).setc(E.left, E.top + F);
                G.setData("width", z, y);
                G.setData("height", D, y);
                F += D
            }
            var H = {
                height: E.height,
                width: E.width - z,
                top: E.top,
                left: E.left + z
            };
            H.dim = Math.min(H.width, H.height);
            if (H.dim != H.height) {
                this.layout.change()
            }
            return H
        },
        layoutH: function(x, G, C, y) {
            var I = 0;
            c.each(x,
            function(w) {
                I += w._area
            });
            var H = I / G,
            D = C.top,
            z = 0;
            for (var B = 0,
            A = x.length; B < A; B++) {
                var E = x[B];
                var G = E._area / H;
                E.getPos(y).setc(C.left + z, D);
                E.setData("width", G, y);
                E.setData("height", H, y);
                z += G
            }
            var F = {
                height: C.height - H,
                width: C.width,
                top: C.top + H,
                left: C.left
            };
            F.dim = Math.min(F.width, F.height);
            if (F.dim != F.width) {
                this.layout.change()
            }
            return F
        }
    });
    g.TM.Strip = new q({
        Implements: g.TM.Area,
        computePositions: function(A, D, x) {
            var w = A.getSubnodes([1, 1], "ignore"),
            z = this.config;
            if (w.length > 0) {
                this.processChildrenLayout(A, w, D, x);
                for (var C = 0,
                B = w.length; C < B; C++) {
                    var F = w[C];
                    var G = z.offset,
                    H = F.getData("height", x) - G - z.titleHeight,
                    y = F.getData("width", x) - G;
                    var E = F.getPos(x);
                    D = {
                        width: y,
                        height: H,
                        top: E.y + z.titleHeight,
                        left: E.x
                    };
                    this.computePositions(F, D, x)
                }
            }
        },
        processChildrenLayout: function(G, w, B, x) {
            var z = B.width * B.height;
            var A, y = w.length,
            C = 0,
            H = [];
            for (A = 0; A < y; A++) {
                H[A] = +w[A].getData("area", x);
                C += H[A]
            }
            for (A = 0; A < y; A++) {
                w[A]._area = z * H[A] / C
            }
            var F = this.layout.horizontal() ? B.width: B.height;
            var E = [w[0]];
            var D = w.slice(1);
            this.stripify(D, E, F, B, x)
        },
        stripify: function(y, B, x, A, z) {
            this.computeDim(y, B, x, A, this.avgAspectRatio, z)
        },
        layoutRow: function(y, x, A, z) {
            if (this.layout.horizontal()) {
                return this.layoutH(y, x, A, z)
            } else {
                return this.layoutV(y, x, A, z)
            }
        },
        layoutV: function(x, G, D, y) {
            var H = 0;
            c.each(x,
            function(w) {
                H += w._area
            });
            var z = H / G,
            E = 0;
            for (var B = 0,
            A = x.length; B < A; B++) {
                var F = x[B];
                var C = F._area / z;
                F.getPos(y).setc(D.left, D.top + (G - C - E));
                F.setData("width", z, y);
                F.setData("height", C, y);
                E += C
            }
            return {
                height: D.height,
                width: D.width - z,
                top: D.top,
                left: D.left + z,
                dim: G
            }
        },
        layoutH: function(x, F, C, y) {
            var H = 0;
            c.each(x,
            function(w) {
                H += w._area
            });
            var G = H / F,
            D = C.height - G,
            z = 0;
            for (var B = 0,
            A = x.length; B < A; B++) {
                var E = x[B];
                var I = E._area / G;
                E.getPos(y).setc(C.left + z, C.top + D);
                E.setData("width", I, y);
                E.setData("height", G, y);
                z += I
            }
            return {
                height: C.height - G,
                width: C.width,
                top: C.top,
                left: C.left,
                dim: F
            }
        }
    });
    g.Icicle = new q({
        compute: function(E) {
            E = E || "current";
            var D = this.graph.getNode(this.root),
            z = this.config,
            H = this.canvas.getSize(),
            w = H.width,
            G = H.height,
            A = z.offset,
            C = z.constrained ? z.levelsToShow: Number.MAX_VALUE;
            this.controller.onBeforeCompute(D);
            e.Util.computeLevels(this.graph, D.id, 0, "ignore");
            var F = 0;
            e.Util.eachLevel(D, 0, false,
            function(J, I) {
                if (I > F) {
                    F = I
                }
            });
            var y = this.graph.getNode(this.clickedNode && this.clickedNode.id || D.id);
            var x = Math.min(F, C - 1);
            var B = y._depth;
            if (this.layout.horizontal()) {
                this.computeSubtree(y, -w / 2, -G / 2, w / (x + 1), G, B, x, E)
            } else {
                this.computeSubtree(y, -w / 2, -G / 2, w, G / (x + 1), B, x, E)
            }
        },
        computeSubtree: function(G, I, F, w, L, E, A, H) {
            G.getPos(H).setc(I, F);
            G.setData("width", w, H);
            G.setData("height", L, H);
            var C, K = 0,
            J = 0;
            var z = e.Util.getSubnodes(G, [1, 1]);
            if (!z.length) {
                return
            }
            c.each(z,
            function(x) {
                J += x.getData("dim")
            });
            for (var D = 0,
            B = z.length; D < B; D++) {
                if (this.layout.horizontal()) {
                    C = L * z[D].getData("dim") / J;
                    this.computeSubtree(z[D], I + w, F, w, C, E, A, H);
                    F += C
                } else {
                    C = w * z[D].getData("dim") / J;
                    this.computeSubtree(z[D], I, F + L, C, L, E, A, H);
                    I += C
                }
            }
        }
    });
    $jit.Icicle = new q({
        Implements: [d, o, g.Icicle],
        layout: {
            orientation: "h",
            vertical: function() {
                return this.orientation == "v"
            },
            horizontal: function() {
                return this.orientation == "h"
            },
            change: function() {
                this.orientation = this.vertical() ? "h": "v"
            }
        },
        initialize: function(w) {
            var x = {
                animate: false,
                orientation: "h",
                offset: 2,
                levelsToShow: Number.MAX_VALUE,
                constrained: false,
                Node: {
                    type: "rectangle",
                    overridable: true
                },
                Edge: {
                    type: "none"
                },
                Label: {
                    type: "Native"
                },
                duration: 700,
                fps: 45
            };
            var z = n("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label");
            this.controller = this.config = c.merge(z, x, w);
            this.layout.orientation = this.config.orientation;
            var y = this.config;
            if (y.useCanvas) {
                this.canvas = y.useCanvas;
                this.config.labelContainer = this.canvas.id + "-label"
            } else {
                this.canvas = new l(this, y);
                this.config.labelContainer = (typeof y.injectInto == "string" ? y.injectInto: y.injectInto.id) + "-label"
            }
            this.graphOptions = {
                complex: true,
                Node: {
                    selected: false,
                    exist: true,
                    drawn: true
                }
            };
            this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
            this.labels = new $jit.Icicle.Label[this.config.Label.type](this);
            this.fx = new $jit.Icicle.Plot(this, $jit.Icicle);
            this.op = new $jit.Icicle.Op(this);
            this.group = new $jit.Icicle.Group(this);
            this.clickedNode = null;
            this.initializeExtras()
        },
        refresh: function() {
            var w = this.config.Label.type;
            if (w != "Native") {
                var x = this;
                this.graph.eachNode(function(y) {
                    x.labels.hideLabel(y, false)
                })
            }
            this.compute();
            this.plot()
        },
        plot: function() {
            this.fx.plot(this.config)
        },
        enter: function(y) {
            if (this.busy) {
                return
            }
            this.busy = true;
            var x = this,
            w = this.config;
            var z = {
                onComplete: function() {
                    if (w.request) {
                        x.compute()
                    }
                    if (w.animate) {
                        x.graph.nodeList.setDataset(["current", "end"], {
                            alpha: [1, 0]
                        });
                        e.Util.eachSubgraph(y,
                        function(A) {
                            A.setData("alpha", 1, "end")
                        },
                        "ignore");
                        x.fx.animate({
                            duration: 500,
                            modes: ["node-property:alpha"],
                            onComplete: function() {
                                x.clickedNode = y;
                                x.compute("end");
                                x.fx.animate({
                                    modes: ["linear", "node-property:width:height"],
                                    duration: 1000,
                                    onComplete: function() {
                                        x.busy = false;
                                        x.clickedNode = y
                                    }
                                })
                            }
                        })
                    } else {
                        x.clickedNode = y;
                        x.busy = false;
                        x.refresh()
                    }
                }
            };
            if (w.request) {
                this.requestNodes(clickedNode, z)
            } else {
                z.onComplete()
            }
        },
        out: function() {
            if (this.busy) {
                return
            }
            var B = this,
            A = e.Util,
            y = this.config,
            D = this.graph,
            x = A.getParents(D.getNode(this.clickedNode && this.clickedNode.id || this.root)),
            z = x[0],
            w = z,
            C = this.clickedNode;
            this.busy = true;
            this.events.hoveredNode = false;
            if (!z) {
                this.busy = false;
                return
            }
            callback = {
                onComplete: function() {
                    B.clickedNode = z;
                    if (y.request) {
                        B.requestNodes(z, {
                            onComplete: function() {
                                B.compute();
                                B.plot();
                                B.busy = false
                            }
                        })
                    } else {
                        B.compute();
                        B.plot();
                        B.busy = false
                    }
                }
            };
            if (y.animate) {
                this.clickedNode = w;
                this.compute("end");
                this.clickedNode = C;
                this.fx.animate({
                    modes: ["linear", "node-property:width:height"],
                    duration: 1000,
                    onComplete: function() {
                        B.clickedNode = w;
                        D.nodeList.setDataset(["current", "end"], {
                            alpha: [0, 1]
                        });
                        A.eachSubgraph(C,
                        function(E) {
                            E.setData("alpha", 1)
                        },
                        "ignore");
                        B.fx.animate({
                            duration: 500,
                            modes: ["node-property:alpha"],
                            onComplete: function() {
                                callback.onComplete()
                            }
                        })
                    }
                })
            } else {
                callback.onComplete()
            }
        },
        requestNodes: function(y, z) {
            var x = c.merge(this.controller, z),
            w = this.config.constrained ? this.config.levelsToShow: Number.MAX_VALUE;
            if (x.request) {
                var B = [],
                A = y._depth;
                e.Util.eachLevel(y, 0, w,
                function(C) {
                    if (C.drawn && !e.Util.anySubnode(C)) {
                        B.push(C);
                        C._level = C._depth - A;
                        if (this.config.constrained) {
                            C._level = w - C._level
                        }
                    }
                });
                this.group.requestNodes(B, x)
            } else {
                x.onComplete()
            }
        }
    });
    $jit.Icicle.Op = new q({
        Implements: e.Op
    });
    $jit.Icicle.Group = new q({
        initialize: function(w) {
            this.viz = w;
            this.canvas = w.canvas;
            this.config = w.config
        },
        requestNodes: function(B, A) {
            var z = 0,
            x = B.length,
            D = {};
            var y = function() {
                A.onComplete()
            };
            var w = this.viz;
            if (x == 0) {
                y()
            }
            for (var C = 0; C < x; C++) {
                D[B[C].id] = B[C];
                A.request(B[C].id, B[C]._level, {
                    onComplete: function(F, E) {
                        if (E && E.children) {
                            E.id = F;
                            w.op.sum(E, {
                                type: "nothing"
                            })
                        }
                        if (++z == x) {
                            e.Util.computeLevels(w.graph, w.root, 0);
                            y()
                        }
                    }
                })
            }
        }
    });
    $jit.Icicle.Plot = new q({
        Implements: e.Plot,
        plot: function(A, y) {
            A = A || this.viz.controller;
            var w = this.viz,
            B = w.graph,
            x = B.getNode(w.clickedNode && w.clickedNode.id || w.root),
            z = x._depth;
            w.canvas.clear();
            this.plotTree(x, c.merge(A, {
                withLabels: true,
                hideLabels: false,
                plotSubtree: function(C, D) {
                    return ! w.config.constrained || (D._depth - z < w.config.levelsToShow)
                }
            }), y)
        }
    });
    $jit.Icicle.Label = {};
    $jit.Icicle.Label.Native = new q({
        Implements: e.Label.Native,
        renderLabel: function(x, y, A) {
            var D = x.getCtx(),
            w = y.getData("width"),
            C = y.getData("height"),
            E = y.getLabelData("size"),
            z = D.measureText(y.name);
            if (C < (E * 1.5) || w < z.width) {
                return
            }
            var B = y.pos.getc(true);
            D.fillText(y.name, B.x + w / 2, B.y + C / 2)
        }
    });
    $jit.Icicle.Label.SVG = new q({
        Implements: e.Label.SVG,
        initialize: function(w) {
            this.viz = w
        },
        placeLabel: function(x, A, y) {
            var C = A.pos.getc(true),
            z = this.viz.canvas;
            var w = z.getSize();
            var B = {
                x: Math.round(C.x + w.width / 2),
                y: Math.round(C.y + w.height / 2)
            };
            x.setAttribute("x", B.x);
            x.setAttribute("y", B.y);
            y.onPlaceLabel(x, A)
        }
    });
    $jit.Icicle.Label.HTML = new q({
        Implements: e.Label.HTML,
        initialize: function(w) {
            this.viz = w
        },
        placeLabel: function(x, B, y) {
            var D = B.pos.getc(true),
            z = this.viz.canvas;
            var w = z.getSize();
            var C = {
                x: Math.round(D.x + w.width / 2),
                y: Math.round(D.y + w.height / 2)
            };
            var A = x.style;
            A.left = C.x + "px";
            A.top = C.y + "px";
            A.display = "";
            y.onPlaceLabel(x, B)
        }
    });
    $jit.Icicle.Plot.NodeTypes = new q({
        none: {
            render: c.empty
        },
        rectangle: {
            render: function(z, x, K) {
                var y = this.viz.config;
                var C = y.offset;
                var w = z.getData("width");
                var H = z.getData("height");
                var B = z.getData("border");
                var G = z.pos.getc(true);
                var F = G.x + C / 2,
                D = G.y + C / 2;
                var J = x.getCtx();
                if (w - C < 2 || H - C < 2) {
                    return
                }
                if (y.cushion) {
                    var A = z.getData("color");
                    var I = J.createRadialGradient(F + (w - C) / 2, D + (H - C) / 2, 1, F + (w - C) / 2, D + (H - C) / 2, w < H ? H: w);
                    var E = c.rgbToHex(c.map(c.hexToRgb(A),
                    function(L) {
                        return L * 0.3 >> 0
                    }));
                    I.addColorStop(0, A);
                    I.addColorStop(1, E);
                    J.fillStyle = I
                }
                if (B) {
                    J.strokeStyle = B;
                    J.lineWidth = 3
                }
                J.fillRect(F, D, Math.max(0, w - C), Math.max(0, H - C));
                B && J.strokeRect(G.x, G.y, w, H)
            },
            contains: function(y, A) {
                if (this.viz.clickedNode && !$jit.Graph.Util.isDescendantOf(y, this.viz.clickedNode.id)) {
                    return false
                }
                var z = y.pos.getc(true),
                x = y.getData("width"),
                w = y.getData("height");
                return this.nodeHelper.rectangle.contains({
                    x: z.x + x / 2,
                    y: z.y + w / 2
                },
                A, x, w)
            }
        }
    });
    $jit.Icicle.Plot.EdgeTypes = new q({
        none: c.empty
    });
    g.ForceDirected = new q({
        getOptions: function(D) {
            var B = this.canvas.getSize();
            var y = B.width,
            A = B.height;
            var C = 0;
            this.graph.eachNode(function(w) {
                C++
            });
            var E = y * A / C,
            z = Math.sqrt(E);
            var x = this.config.levelDistance;
            return {
                width: y,
                height: A,
                tstart: y * 0.1,
                nodef: function(w) {
                    return E / (w || 1)
                },
                edgef: function(w) {
                    return z * (w - x)
                }
            }
        },
        compute: function(x, y) {
            var z = c.splat(x || ["current", "start", "end"]);
            var w = this.getOptions();
            f.compute(this.graph, z, this.config);
            this.graph.computeLevels(this.root, 0, "ignore");
            this.graph.eachNode(function(A) {
                c.each(z,
                function(B) {
                    var C = A.getPos(B);
                    if (C.equals(p.KER)) {
                        C.x = w.width / 5 * (Math.random() - 0.5);
                        C.y = w.height / 5 * (Math.random() - 0.5)
                    }
                    A.disp = {};
                    c.each(z,
                    function(D) {
                        A.disp[D] = r(0, 0)
                    })
                })
            });
            this.computePositions(z, w, y)
        },
        computePositions: function(A, y, B) {
            var C = this.config.iterations,
            x = 0,
            z = this;
            if (B) { (function w() {
                    for (var E = B.iter,
                    D = 0; D < E; D++) {
                        y.t = y.tstart * (1 - x++/(C-1));z.computePositionStep(A,y);if(x>=C){B.onComplete();return}}B.onStep(Math.round(x/ (C - 1) * 100));
                        setTimeout(w, 1)
                    })()
                } else {
                    for (; x < C; x++) {
                        y.t = y.tstart * (1 - x / (C - 1));
                        this.computePositionStep(A, y)
                    }
                }
            },
            computePositionStep: function(D, w) {
                var E = this.graph;
                var y = Math.min,
                C = Math.max;
                var B = r(0, 0);
                E.eachNode(function(G) {
                    c.each(D,
                    function(H) {
                        G.disp[H].x = 0;
                        G.disp[H].y = 0
                    });
                    E.eachNode(function(H) {
                        if (H.id != G.id) {
                            c.each(D,
                            function(L) {
                                var J = G.getPos(L),
                                I = H.getPos(L);
                                B.x = J.x - I.x;
                                B.y = J.y - I.y;
                                var K = B.norm() || 1;
                                G.disp[L].$add(B.$scale(w.nodef(K) / K))
                            })
                        }
                    })
                });
                var x = !!E.getNode(this.root).visited;
                E.eachNode(function(G) {
                    G.eachAdjacency(function(H) {
                        var I = H.nodeTo;
                        if ( !! I.visited === x) {
                            c.each(D,
                            function(M) {
                                var K = G.getPos(M),
                                J = I.getPos(M);
                                B.x = K.x - J.x;
                                B.y = K.y - J.y;
                                var L = B.norm() || 1;
                                G.disp[M].$add(B.$scale( - w.edgef(L) / L));
                                I.disp[M].$add(B.$scale( - 1))
                            })
                        }
                    });
                    G.visited = !x
                });
                var F = w.t,
                z = w.width / 2,
                A = w.height / 2;
                E.eachNode(function(G) {
                    c.each(D,
                    function(J) {
                        var H = G.disp[J];
                        var I = H.norm() || 1;
                        var J = G.getPos(J);
                        J.$add(r(H.x * y(Math.abs(H.x), F) / I, H.y * y(Math.abs(H.y), F) / I));
                        J.x = y(z, C( - z, J.x));
                        J.y = y(A, C( - A, J.y))
                    })
                })
            }
        });
        $jit.ForceDirected = new q({
            Implements: [d, o, g.ForceDirected],
            initialize: function(x) {
                var w = $jit.ForceDirected;
                var y = {
                    iterations: 50,
                    levelDistance: 50
                };
                this.controller = this.config = c.merge(n("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), y, x);
                var z = this.config;
                if (z.useCanvas) {
                    this.canvas = z.useCanvas;
                    this.config.labelContainer = this.canvas.id + "-label"
                } else {
                    if (z.background) {
                        z.background = c.merge({
                            type: "Circles"
                        },
                        z.background)
                    }
                    this.canvas = new l(this, z);
                    this.config.labelContainer = (typeof z.injectInto == "string" ? z.injectInto: z.injectInto.id) + "-label"
                }
                this.graphOptions = {
                    complex: true,
                    Node: {
                        selected: false,
                        exist: true,
                        drawn: true
                    }
                };
                this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
                this.labels = new w.Label[z.Label.type](this);
                this.fx = new w.Plot(this, w);
                this.op = new w.Op(this);
                this.json = null;
                this.busy = false;
                this.initializeExtras()
            },
            refresh: function() {
                this.compute();
                this.plot()
            },
            reposition: function() {
                this.compute("end")
            },
            computeIncremental: function(w) {
                w = c.merge({
                    iter: 20,
                    property: "end",
                    onStep: c.empty,
                    onComplete: c.empty
                },
                w || {});
                this.config.onBeforeCompute(this.graph.getNode(this.root));
                this.compute(w.property, w)
            },
            plot: function() {
                this.fx.plot()
            },
            animate: function(w) {
                this.fx.animate(c.merge({
                    modes: ["linear"]
                },
                w || {}))
            }
        });
        $jit.ForceDirected.$extend = true; (function(w) {
            w.Op = new q({
                Implements: e.Op
            });
            w.Plot = new q({
                Implements: e.Plot
            });
            w.Label = {};
            w.Label.Native = new q({
                Implements: e.Label.Native
            });
            w.Label.SVG = new q({
                Implements: e.Label.SVG,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(H, B, C) {
                    var F = B.pos.getc(true),
                    y = this.viz.canvas,
                    z = y.translateOffsetX,
                    x = y.translateOffsetY,
                    G = y.scaleOffsetX,
                    E = y.scaleOffsetY,
                    D = y.getSize();
                    var A = {
                        x: Math.round(F.x * G + z + D.width / 2),
                        y: Math.round(F.y * E + x + D.height / 2)
                    };
                    H.setAttribute("x", A.x);
                    H.setAttribute("y", A.y);
                    C.onPlaceLabel(H, B)
                }
            });
            w.Label.HTML = new q({
                Implements: e.Label.HTML,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(I, C, D) {
                    var G = C.pos.getc(true),
                    z = this.viz.canvas,
                    A = z.translateOffsetX,
                    y = z.translateOffsetY,
                    H = z.scaleOffsetX,
                    F = z.scaleOffsetY,
                    E = z.getSize();
                    var B = {
                        x: Math.round(G.x * H + A + E.width / 2),
                        y: Math.round(G.y * F + y + E.height / 2)
                    };
                    var x = I.style;
                    x.left = B.x + "px";
                    x.top = B.y + "px";
                    x.display = this.fitsInCanvas(B, z) ? "": "none";
                    D.onPlaceLabel(I, C)
                }
            });
            w.Plot.NodeTypes = new q({
                none: {
                    render: c.empty,
                    contains: c.lambda(false)
                },
                circle: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.circle.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.circle.contains(z, A, y)
                    }
                },
                ellipse: {
                    render: function(A, y) {
                        var B = A.pos.getc(true),
                        z = A.getData("width"),
                        x = A.getData("height");
                        this.nodeHelper.ellipse.render("fill", B, z, x, y)
                    },
                    contains: function(z, B) {
                        var A = z.pos.getc(true),
                        y = z.getData("width"),
                        x = z.getData("height");
                        return this.nodeHelper.ellipse.contains(A, B, y, x)
                    }
                },
                square: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.square.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.square.contains(z, A, y)
                    }
                },
                rectangle: {
                    render: function(A, y) {
                        var B = A.pos.getc(true),
                        z = A.getData("width"),
                        x = A.getData("height");
                        this.nodeHelper.rectangle.render("fill", B, z, x, y)
                    },
                    contains: function(z, B) {
                        var A = z.pos.getc(true),
                        y = z.getData("width"),
                        x = z.getData("height");
                        return this.nodeHelper.rectangle.contains(A, B, y, x)
                    }
                },
                triangle: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.triangle.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.triangle.contains(z, A, y)
                    }
                },
                star: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.star.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.star.contains(z, A, y)
                    }
                }
            });
            w.Plot.EdgeTypes = new q({
                none: c.empty,
                line: {
                    render: function(x, y) {
                        var A = x.nodeFrom.pos.getc(true),
                        z = x.nodeTo.pos.getc(true);
                        this.edgeHelper.line.render(A, z, y)
                    },
                    contains: function(x, A) {
                        var z = x.nodeFrom.pos.getc(true),
                        y = x.nodeTo.pos.getc(true);
                        return this.edgeHelper.line.contains(z, y, A, this.edge.epsilon)
                    }
                },
                arrow: {
                    render: function(y, z) {
                        var D = y.nodeFrom.pos.getc(true),
                        C = y.nodeTo.pos.getc(true),
                        B = y.getData("dim"),
                        A = y.data.$direction,
                        x = (A && A.length > 1 && A[0] != y.nodeFrom.id);
                        this.edgeHelper.arrow.render(D, C, B, x, z)
                    },
                    contains: function(x, A) {
                        var z = x.nodeFrom.pos.getc(true),
                        y = x.nodeTo.pos.getc(true);
                        return this.edgeHelper.arrow.contains(z, y, A, this.edge.epsilon)
                    }
                }
            })
        })($jit.ForceDirected);
        $jit.TM = {};
        var v = $jit.TM;
        $jit.TM.$extend = true;
        v.Base = {
            layout: {
                orientation: "h",
                vertical: function() {
                    return this.orientation == "v"
                },
                horizontal: function() {
                    return this.orientation == "h"
                },
                change: function() {
                    this.orientation = this.vertical() ? "h": "v"
                }
            },
            initialize: function(w) {
                var x = {
                    orientation: "h",
                    titleHeight: 13,
                    offset: 2,
                    levelsToShow: 0,
                    constrained: false,
                    animate: false,
                    Node: {
                        type: "rectangle",
                        overridable: true,
                        width: 3,
                        height: 3,
                        color: "#444"
                    },
                    Label: {
                        textAlign: "center",
                        textBaseline: "top"
                    },
                    Edge: {
                        type: "none"
                    },
                    duration: 700,
                    fps: 45
                };
                this.controller = this.config = c.merge(n("Canvas", "Node", "Edge", "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), x, w);
                this.layout.orientation = this.config.orientation;
                var y = this.config;
                if (y.useCanvas) {
                    this.canvas = y.useCanvas;
                    this.config.labelContainer = this.canvas.id + "-label"
                } else {
                    if (y.background) {
                        y.background = c.merge({
                            type: "Circles"
                        },
                        y.background)
                    }
                    this.canvas = new l(this, y);
                    this.config.labelContainer = (typeof y.injectInto == "string" ? y.injectInto: y.injectInto.id) + "-label"
                }
                this.graphOptions = {
                    complex: true,
                    Node: {
                        selected: false,
                        exist: true,
                        drawn: true
                    }
                };
                this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
                this.labels = new v.Label[y.Label.type](this);
                this.fx = new v.Plot(this);
                this.op = new v.Op(this);
                this.group = new v.Group(this);
                this.geom = new v.Geom(this);
                this.clickedNode = null;
                this.busy = false;
                this.initializeExtras()
            },
            refresh: function() {
                if (this.busy) {
                    return
                }
                this.busy = true;
                var x = this;
                if (this.config.animate) {
                    this.compute("end");
                    this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root));
                    this.fx.animate(c.merge(this.config, {
                        modes: ["linear", "node-property:width:height"],
                        onComplete: function() {
                            x.busy = false
                        }
                    }))
                } else {
                    var w = this.config.Label.type;
                    if (w != "Native") {
                        var x = this;
                        this.graph.eachNode(function(y) {
                            x.labels.hideLabel(y, false)
                        })
                    }
                    this.busy = false;
                    this.compute();
                    this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root));
                    this.plot()
                }
            },
            plot: function() {
                this.fx.plot()
            },
            leaf: function(w) {
                return w.getSubnodes([1, 1], "ignore").length == 0
            },
            enter: function(C) {
                if (this.busy) {
                    return
                }
                this.busy = true;
                var y = this,
                x = this.config,
                A = this.graph,
                w = C,
                z = this.clickedNode;
                var B = {
                    onComplete: function() {
                        if (x.levelsToShow > 0) {
                            y.geom.setRightLevelToShow(C)
                        }
                        if (x.levelsToShow > 0 || x.request) {
                            y.compute()
                        }
                        if (x.animate) {
                            A.nodeList.setData("alpha", 0, "end");
                            C.eachSubgraph(function(D) {
                                D.setData("alpha", 1, "end")
                            },
                            "ignore");
                            y.fx.animate({
                                duration: 500,
                                modes: ["node-property:alpha"],
                                onComplete: function() {
                                    y.clickedNode = w;
                                    y.compute("end");
                                    y.clickedNode = z;
                                    y.fx.animate({
                                        modes: ["linear", "node-property:width:height"],
                                        duration: 1000,
                                        onComplete: function() {
                                            y.busy = false;
                                            y.clickedNode = w
                                        }
                                    })
                                }
                            })
                        } else {
                            y.busy = false;
                            y.clickedNode = C;
                            y.refresh()
                        }
                    }
                };
                if (x.request) {
                    this.requestNodes(w, B)
                } else {
                    B.onComplete()
                }
            },
            out: function() {
                if (this.busy) {
                    return
                }
                this.busy = true;
                this.events.hoveredNode = false;
                var A = this,
                y = this.config,
                C = this.graph,
                x = C.getNode(this.clickedNode && this.clickedNode.id || this.root).getParents(),
                z = x[0],
                w = z,
                B = this.clickedNode;
                if (!z) {
                    this.busy = false;
                    return
                }
                callback = {
                    onComplete: function() {
                        A.clickedNode = z;
                        if (y.request) {
                            A.requestNodes(z, {
                                onComplete: function() {
                                    A.compute();
                                    A.plot();
                                    A.busy = false
                                }
                            })
                        } else {
                            A.compute();
                            A.plot();
                            A.busy = false
                        }
                    }
                };
                if (y.levelsToShow > 0) {
                    this.geom.setRightLevelToShow(z)
                }
                if (y.animate) {
                    this.clickedNode = w;
                    this.compute("end");
                    this.clickedNode = B;
                    this.fx.animate({
                        modes: ["linear", "node-property:width:height"],
                        duration: 1000,
                        onComplete: function() {
                            A.clickedNode = w;
                            C.eachNode(function(D) {
                                D.setDataset(["current", "end"], {
                                    alpha: [0, 1]
                                })
                            },
                            "ignore");
                            B.eachSubgraph(function(D) {
                                D.setData("alpha", 1)
                            },
                            "ignore");
                            A.fx.animate({
                                duration: 500,
                                modes: ["node-property:alpha"],
                                onComplete: function() {
                                    callback.onComplete()
                                }
                            })
                        }
                    })
                } else {
                    callback.onComplete()
                }
            },
            requestNodes: function(y, z) {
                var x = c.merge(this.controller, z),
                w = this.config.levelsToShow;
                if (x.request) {
                    var B = [],
                    A = y._depth;
                    y.eachLevel(0, w,
                    function(D) {
                        var C = w - (D._depth - A);
                        if (D.drawn && !D.anySubnode() && C > 0) {
                            B.push(D);
                            D._level = C
                        }
                    });
                    this.group.requestNodes(B, x)
                } else {
                    x.onComplete()
                }
            }
        };
        v.Op = new q({
            Implements: e.Op,
            initialize: function(w) {
                this.viz = w
            }
        });
        v.Geom = new q({
            Implements: e.Geom,
            getRightLevelToShow: function() {
                return this.viz.config.levelsToShow
            },
            setRightLevelToShow: function(x) {
                var y = this.getRightLevelToShow(),
                w = this.viz.labels;
                x.eachLevel(0, y + 1,
                function(A) {
                    var z = A._depth - x._depth;
                    if (z > y) {
                        A.drawn = false;
                        A.exist = false;
                        A.ignore = true;
                        w.hideLabel(A, false)
                    } else {
                        A.drawn = true;
                        A.exist = true;
                        delete A.ignore
                    }
                });
                x.drawn = true;
                delete x.ignore
            }
        });
        v.Group = new q({
            initialize: function(w) {
                this.viz = w;
                this.canvas = w.canvas;
                this.config = w.config
            },
            requestNodes: function(B, A) {
                var z = 0,
                x = B.length,
                D = {};
                var y = function() {
                    A.onComplete()
                };
                var w = this.viz;
                if (x == 0) {
                    y()
                }
                for (var C = 0; C < x; C++) {
                    D[B[C].id] = B[C];
                    A.request(B[C].id, B[C]._level, {
                        onComplete: function(F, E) {
                            if (E && E.children) {
                                E.id = F;
                                w.op.sum(E, {
                                    type: "nothing"
                                })
                            }
                            if (++z == x) {
                                w.graph.computeLevels(w.root, 0);
                                y()
                            }
                        }
                    })
                }
            }
        });
        v.Plot = new q({
            Implements: e.Plot,
            initialize: function(w) {
                this.viz = w;
                this.config = w.config;
                this.node = this.config.Node;
                this.edge = this.config.Edge;
                this.animation = new u;
                this.nodeTypes = new v.Plot.NodeTypes;
                this.edgeTypes = new v.Plot.EdgeTypes;
                this.labels = w.labels
            },
            plot: function(y, x) {
                var w = this.viz,
                z = w.graph;
                w.canvas.clear();
                this.plotTree(z.getNode(w.clickedNode && w.clickedNode.id || w.root), c.merge(w.config, y || {},
                {
                    withLabels: true,
                    hideLabels: false,
                    plotSubtree: function(B, A) {
                        return B.anySubnode("exist")
                    }
                }), x)
            }
        });
        v.Label = {};
        v.Label.Native = new q({
            Implements: e.Label.Native,
            initialize: function(w) {
                this.config = w.config;
                this.leaf = w.leaf
            },
            renderLabel: function(z, A, B) {
                if (!this.leaf(A) && !this.config.titleHeight) {
                    return
                }
                var D = A.pos.getc(true),
                G = z.getCtx(),
                w = A.getData("width"),
                F = A.getData("height"),
                E = D.x + w / 2,
                C = D.y;
                G.fillText(A.name, E, C, w)
            }
        });
        v.Label.SVG = new q({
            Implements: e.Label.SVG,
            initialize: function(w) {
                this.viz = w;
                this.leaf = w.leaf;
                this.config = w.config
            },
            placeLabel: function(G, A, B) {
                var E = A.pos.getc(true),
                x = this.viz.canvas,
                y = x.translateOffsetX,
                w = x.translateOffsetY,
                F = x.scaleOffsetX,
                D = x.scaleOffsetY,
                C = x.getSize();
                var z = {
                    x: Math.round(E.x * F + y + C.width / 2),
                    y: Math.round(E.y * D + w + C.height / 2)
                };
                G.setAttribute("x", z.x);
                G.setAttribute("y", z.y);
                if (!this.leaf(A) && !this.config.titleHeight) {
                    G.style.display = "none"
                }
                B.onPlaceLabel(G, A)
            }
        });
        v.Label.HTML = new q({
            Implements: e.Label.HTML,
            initialize: function(w) {
                this.viz = w;
                this.leaf = w.leaf;
                this.config = w.config
            },
            placeLabel: function(H, B, C) {
                var F = B.pos.getc(true),
                y = this.viz.canvas,
                z = y.translateOffsetX,
                x = y.translateOffsetY,
                G = y.scaleOffsetX,
                E = y.scaleOffsetY,
                D = y.getSize();
                var A = {
                    x: Math.round(F.x * G + z + D.width / 2),
                    y: Math.round(F.y * E + x + D.height / 2)
                };
                var w = H.style;
                w.left = A.x + "px";
                w.top = A.y + "px";
                w.width = B.getData("width") * G + "px";
                w.height = B.getData("height") * E + "px";
                w.zIndex = B._depth * 100;
                w.display = "";
                if (!this.leaf(B) && !this.config.titleHeight) {
                    H.style.display = "none"
                }
                C.onPlaceLabel(H, B)
            }
        });
        v.Plot.NodeTypes = new q({
            none: {
                render: c.empty
            },
            rectangle: {
                render: function(z, x, M) {
                    var D = this.viz.leaf(z),
                    y = this.config,
                    I = y.offset,
                    C = y.titleHeight,
                    H = z.pos.getc(true),
                    w = z.getData("width"),
                    J = z.getData("height"),
                    B = z.getData("border"),
                    L = x.getCtx(),
                    G = H.x + I / 2,
                    E = H.y + I / 2;
                    if (w <= I || J <= I) {
                        return
                    }
                    if (D) {
                        if (y.cushion) {
                            var K = L.createRadialGradient(G + (w - I) / 2, E + (J - I) / 2, 1, G + (w - I) / 2, E + (J - I) / 2, w < J ? J: w);
                            var A = z.getData("color");
                            var F = c.rgbToHex(c.map(c.hexToRgb(A),
                            function(N) {
                                return N * 0.2 >> 0
                            }));
                            K.addColorStop(0, A);
                            K.addColorStop(1, F);
                            L.fillStyle = K
                        }
                        L.fillRect(G, E, w - I, J - I);
                        if (B) {
                            L.save();
                            L.strokeStyle = B;
                            L.strokeRect(G, E, w - I, J - I);
                            L.restore()
                        }
                    } else {
                        if (C > 0) {
                            L.fillRect(H.x + I / 2, H.y + I / 2, w - I, C - I);
                            if (B) {
                                L.save();
                                L.strokeStyle = B;
                                L.strokeRect(H.x + I / 2, H.y + I / 2, w - I, J - I);
                                L.restore()
                            }
                        }
                    }
                },
                contains: function(z, B) {
                    if (this.viz.clickedNode && !z.isDescendantOf(this.viz.clickedNode.id) || z.ignore) {
                        return false
                    }
                    var A = z.pos.getc(true),
                    y = z.getData("width"),
                    x = this.viz.leaf(z),
                    w = x ? z.getData("height") : this.config.titleHeight;
                    return this.nodeHelper.rectangle.contains({
                        x: A.x + y / 2,
                        y: A.y + w / 2
                    },
                    B, y, w)
                }
            }
        });
        v.Plot.EdgeTypes = new q({
            none: c.empty
        });
        v.SliceAndDice = new q({
            Implements: [d, o, v.Base, g.TM.SliceAndDice]
        });
        v.Squarified = new q({
            Implements: [d, o, v.Base, g.TM.Squarified]
        });
        v.Strip = new q({
            Implements: [d, o, v.Base, g.TM.Strip]
        });
        $jit.RGraph = new q({
            Implements: [d, o, g.Radial],
            initialize: function(w) {
                var x = $jit.RGraph;
                var y = {
                    interpolation: "linear",
                    levelDistance: 100
                };
                this.controller = this.config = c.merge(n("Canvas", "Node", "Edge", "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), y, w);
                var z = this.config;
                if (z.useCanvas) {
                    this.canvas = z.useCanvas;
                    this.config.labelContainer = this.canvas.id + "-label"
                } else {
                    if (z.background) {
                        z.background = c.merge({
                            type: "Circles"
                        },
                        z.background)
                    }
                    this.canvas = new l(this, z);
                    this.config.labelContainer = (typeof z.injectInto == "string" ? z.injectInto: z.injectInto.id) + "-label"
                }
                this.graphOptions = {
                    complex: false,
                    Node: {
                        selected: false,
                        exist: true,
                        drawn: true
                    }
                };
                this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
                this.labels = new x.Label[z.Label.type](this);
                this.fx = new x.Plot(this, x);
                this.op = new x.Op(this);
                this.json = null;
                this.root = null;
                this.busy = false;
                this.parent = false;
                this.initializeExtras()
            },
            createLevelDistanceFunc: function() {
                var w = this.config.levelDistance;
                return function(x) {
                    return (x._depth + 1) * w
                }
            },
            refresh: function() {
                this.compute();
                this.plot()
            },
            reposition: function() {
                this.compute("end")
            },
            plot: function() {
                this.fx.plot()
            },
            getNodeAndParentAngle: function(D) {
                var y = false;
                var C = this.graph.getNode(D);
                var A = C.getParents();
                var z = (A.length > 0) ? A[0] : false;
                if (z) {
                    var w = z.pos.getc(),
                    B = C.pos.getc();
                    var x = w.add(B.scale( - 1));
                    y = Math.atan2(x.y, x.x);
                    if (y < 0) {
                        y += 2 * Math.PI
                    }
                }
                return {
                    parent: z,
                    theta: y
                }
            },
            tagChildren: function(A, C) {
                if (A.angleSpan) {
                    var B = [];
                    A.eachAdjacency(function(D) {
                        B.push(D.nodeTo)
                    },
                    "ignore");
                    var w = B.length;
                    for (var z = 0; z < w && C != B[z].id; z++) {}
                    for (var y = (z + 1) % w, x = 0; C != B[y].id; y = (y + 1) % w) {
                        B[y].dist = x++
                    }
                }
            },
            onClick: function(A, x) {
                if (this.root != A && !this.busy) {
                    this.busy = true;
                    this.root = A;
                    that = this;
                    this.controller.onBeforeCompute(this.graph.getNode(A));
                    var y = this.getNodeAndParentAngle(A);
                    this.tagChildren(y.parent, A);
                    this.parent = y.parent;
                    this.compute("end");
                    var w = y.theta - y.parent.endPos.theta;
                    this.graph.eachNode(function(B) {
                        B.endPos.set(B.endPos.getp().add(k(w, 0)))
                    });
                    var z = this.config.interpolation;
                    x = c.merge({
                        onComplete: c.empty
                    },
                    x || {});
                    this.fx.animate(c.merge({
                        hideLabels: true,
                        modes: [z]
                    },
                    x, {
                        onComplete: function() {
                            that.busy = false;
                            x.onComplete()
                        }
                    }))
                }
            }
        });
        $jit.RGraph.$extend = true; (function(w) {
            w.Op = new q({
                Implements: e.Op
            });
            w.Plot = new q({
                Implements: e.Plot
            });
            w.Label = {};
            w.Label.Native = new q({
                Implements: e.Label.Native
            });
            w.Label.SVG = new q({
                Implements: e.Label.SVG,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(H, B, C) {
                    var F = B.pos.getc(true),
                    y = this.viz.canvas,
                    z = y.translateOffsetX,
                    x = y.translateOffsetY,
                    G = y.scaleOffsetX,
                    E = y.scaleOffsetY,
                    D = y.getSize();
                    var A = {
                        x: Math.round(F.x * G + z + D.width / 2),
                        y: Math.round(F.y * E + x + D.height / 2)
                    };
                    H.setAttribute("x", A.x);
                    H.setAttribute("y", A.y);
                    C.onPlaceLabel(H, B)
                }
            });
            w.Label.HTML = new q({
                Implements: e.Label.HTML,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(I, C, D) {
                    var G = C.pos.getc(true),
                    z = this.viz.canvas,
                    A = z.translateOffsetX,
                    y = z.translateOffsetY,
                    H = z.scaleOffsetX,
                    F = z.scaleOffsetY,
                    E = z.getSize();
                    var B = {
                        x: Math.round(G.x * H + A + E.width / 2),
                        y: Math.round(G.y * F + y + E.height / 2)
                    };
                    var x = I.style;
                    x.left = B.x + "px";
                    x.top = B.y + "px";
                    x.display = this.fitsInCanvas(B, z) ? "": "none";
                    D.onPlaceLabel(I, C)
                }
            });
            w.Plot.NodeTypes = new q({
                none: {
                    render: c.empty,
                    contains: c.lambda(false)
                },
                circle: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.circle.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.circle.contains(z, A, y)
                    }
                },
                ellipse: {
                    render: function(A, y) {
                        var B = A.pos.getc(true),
                        z = A.getData("width"),
                        x = A.getData("height");
                        this.nodeHelper.ellipse.render("fill", B, z, x, y)
                    },
                    contains: function(z, B) {
                        var A = z.pos.getc(true),
                        y = z.getData("width"),
                        x = z.getData("height");
                        return this.nodeHelper.ellipse.contains(A, B, y, x)
                    }
                },
                square: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.square.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.square.contains(z, A, y)
                    }
                },
                rectangle: {
                    render: function(A, y) {
                        var B = A.pos.getc(true),
                        z = A.getData("width"),
                        x = A.getData("height");
                        this.nodeHelper.rectangle.render("fill", B, z, x, y)
                    },
                    contains: function(z, B) {
                        var A = z.pos.getc(true),
                        y = z.getData("width"),
                        x = z.getData("height");
                        return this.nodeHelper.rectangle.contains(A, B, y, x)
                    }
                },
                triangle: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.triangle.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.triangle.contains(z, A, y)
                    }
                },
                star: {
                    render: function(y, x) {
                        var A = y.pos.getc(true),
                        z = y.getData("dim");
                        this.nodeHelper.star.render("fill", A, z, x)
                    },
                    contains: function(x, A) {
                        var z = x.pos.getc(true),
                        y = x.getData("dim");
                        return this.nodeHelper.star.contains(z, A, y)
                    }
                }
            });
            w.Plot.EdgeTypes = new q({
                none: c.empty,
                line: {
                    render: function(x, y) {
                        var A = x.nodeFrom.pos.getc(true),
                        z = x.nodeTo.pos.getc(true);
                        this.edgeHelper.line.render(A, z, y)
                    },
                    contains: function(x, A) {
                        var z = x.nodeFrom.pos.getc(true),
                        y = x.nodeTo.pos.getc(true);
                        return this.edgeHelper.line.contains(z, y, A, this.edge.epsilon)
                    }
                },
                arrow: {
                    render: function(y, z) {
                        var D = y.nodeFrom.pos.getc(true),
                        C = y.nodeTo.pos.getc(true),
                        B = y.getData("dim"),
                        A = y.data.$direction,
                        x = (A && A.length > 1 && A[0] != y.nodeFrom.id);
                        this.edgeHelper.arrow.render(D, C, B, x, z)
                    },
                    contains: function(x, A) {
                        var z = x.nodeFrom.pos.getc(true),
                        y = x.nodeTo.pos.getc(true);
                        return this.edgeHelper.arrow.contains(z, y, A, this.edge.epsilon)
                    }
                }
            })
        })($jit.RGraph);
        p.prototype.moebiusTransformation = function(y) {
            var w = this.add(y);
            var x = y.$conjugate().$prod(this);
            x.x++;
            return w.$div(x)
        };
        e.Util.moebiusTransformation = function(y, A, z, x, w) {
            this.eachNode(y,
            function(C) {
                for (var B = 0; B < z.length; B++) {
                    var E = A[B].scale( - 1),
                    D = x ? x: z[B];
                    C.getPos(z[B]).set(C.getPos(D).getc().moebiusTransformation(E))
                }
            },
            w)
        };
        $jit.Hypertree = new q({
            Implements: [d, o, g.Radial],
            initialize: function(w) {
                var z = $jit.Hypertree;
                var x = {
                    radius: "auto",
                    offset: 0,
                    Edge: {
                        type: "hyperline"
                    },
                    duration: 1500,
                    fps: 35
                };
                this.controller = this.config = c.merge(n("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), x, w);
                var y = this.config;
                if (y.useCanvas) {
                    this.canvas = y.useCanvas;
                    this.config.labelContainer = this.canvas.id + "-label"
                } else {
                    if (y.background) {
                        y.background = c.merge({
                            type: "Circles"
                        },
                        y.background)
                    }
                    this.canvas = new l(this, y);
                    this.config.labelContainer = (typeof y.injectInto == "string" ? y.injectInto: y.injectInto.id) + "-label"
                }
                this.graphOptions = {
                    complex: false,
                    Node: {
                        selected: false,
                        exist: true,
                        drawn: true
                    }
                };
                this.graph = new e(this.graphOptions, this.config.Node, this.config.Edge);
                this.labels = new z.Label[y.Label.type](this);
                this.fx = new z.Plot(this, z);
                this.op = new z.Op(this);
                this.json = null;
                this.root = null;
                this.busy = false;
                this.initializeExtras()
            },
            createLevelDistanceFunc: function() {
                var A = this.getRadius();
                var C = 0,
                w = Math.max,
                x = this.config;
                this.graph.eachNode(function(D) {
                    C = w(D._depth, C)
                },
                "ignore");
                C++;
                var B = function(D) {
                    return function(F) {
                        F.scale = A;
                        var H = F._depth + 1;
                        var G = 0,
                        E = Math.pow;
                        while (H) {
                            G += E(D, H--)
                        }
                        return G - x.offset
                    }
                };
                for (var z = 0.51; z <= 1; z += 0.01) {
                    var y = (1 - Math.pow(z, C)) / (1 - z);
                    if (y >= 2) {
                        return B(z - 0.01)
                    }
                }
                return B(0.75)
            },
            getRadius: function() {
                var w = this.config.radius;
                if (w !== "auto") {
                    return w
                }
                var x = this.canvas.getSize();
                return Math.min(x.width, x.height) / 2
            },
            refresh: function(w) {
                if (w) {
                    this.reposition();
                    this.graph.eachNode(function(x) {
                        x.startPos.rho = x.pos.rho = x.endPos.rho;
                        x.startPos.theta = x.pos.theta = x.endPos.theta
                    })
                } else {
                    this.compute()
                }
                this.plot()
            },
            reposition: function() {
                this.compute("end");
                var w = this.graph.getNode(this.root).pos.getc().scale( - 1);
                e.Util.moebiusTransformation(this.graph, [w], ["end"], "end", "ignore");
                this.graph.eachNode(function(x) {
                    if (x.ignore) {
                        x.endPos.rho = x.pos.rho;
                        x.endPos.theta = x.pos.theta
                    }
                })
            },
            plot: function() {
                this.fx.plot()
            },
            onClick: function(y, w) {
                var x = this.graph.getNode(y).pos.getc(true);
                this.move(x, w)
            },
            move: function(A, y) {
                var x = r(A.x, A.y);
                if (this.busy === false && x.norm() < 1) {
                    this.busy = true;
                    var w = this.graph.getClosestNodeToPos(x),
                    z = this;
                    this.graph.computeLevels(w.id, 0);
                    this.controller.onBeforeCompute(w);
                    y = c.merge({
                        onComplete: c.empty
                    },
                    y || {});
                    this.fx.animate(c.merge({
                        modes: ["moebius"],
                        hideLabels: true
                    },
                    y, {
                        onComplete: function() {
                            z.busy = false;
                            y.onComplete()
                        }
                    }), x)
                }
            }
        });
        $jit.Hypertree.$extend = true; (function(w) {
            w.Op = new q({
                Implements: e.Op
            });
            w.Plot = new q({
                Implements: e.Plot
            });
            w.Label = {};
            w.Label.Native = new q({
                Implements: e.Label.Native,
                initialize: function(x) {
                    this.viz = x
                },
                renderLabel: function(z, B, y) {
                    var x = z.getCtx();
                    var C = B.pos.getc(true);
                    var A = this.viz.getRadius();
                    x.fillText(B.name, C.x * A, C.y * A)
                }
            });
            w.Label.SVG = new q({
                Implements: e.Label.SVG,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(I, C, D) {
                    var G = C.pos.getc(true),
                    z = this.viz.canvas,
                    A = z.translateOffsetX,
                    y = z.translateOffsetY,
                    H = z.scaleOffsetX,
                    F = z.scaleOffsetY,
                    E = z.getSize(),
                    x = this.viz.getRadius();
                    var B = {
                        x: Math.round((G.x * H) * x + A + E.width / 2),
                        y: Math.round((G.y * F) * x + y + E.height / 2)
                    };
                    I.setAttribute("x", B.x);
                    I.setAttribute("y", B.y);
                    D.onPlaceLabel(I, C)
                }
            });
            w.Label.HTML = new q({
                Implements: e.Label.HTML,
                initialize: function(x) {
                    this.viz = x
                },
                placeLabel: function(J, D, E) {
                    var H = D.pos.getc(true),
                    A = this.viz.canvas,
                    B = A.translateOffsetX,
                    z = A.translateOffsetY,
                    I = A.scaleOffsetX,
                    G = A.scaleOffsetY,
                    F = A.getSize(),
                    x = this.viz.getRadius();
                    var C = {
                        x: Math.round((H.x * I) * x + B + F.width / 2),
                        y: Math.round((H.y * G) * x + z + F.height / 2)
                    };
                    var y = J.style;
                    y.left = C.x + "px";
                    y.top = C.y + "px";
                    y.display = this.fitsInCanvas(C, A) ? "": "none";
                    E.onPlaceLabel(J, D)
                }
            });
            w.Plot.NodeTypes = new q({
                none: {
                    render: c.empty,
                    contains: c.lambda(false)
                },
                circle: {
                    render: function(z, x) {
                        var y = this.node,
                        B = z.getData("dim"),
                        A = z.pos.getc();
                        B = y.transform ? B * (1 - A.squaredNorm()) : B;
                        A.$scale(z.scale);
                        if (B > 0.2) {
                            this.nodeHelper.circle.render("fill", A, B, x)
                        }
                    },
                    contains: function(x, A) {
                        var y = x.getData("dim"),
                        z = x.pos.getc().$scale(x.scale);
                        return this.nodeHelper.circle.contains(z, A, y)
                    }
                },
                ellipse: {
                    render: function(A, y) {
                        var B = A.pos.getc().$scale(A.scale),
                        z = A.getData("width"),
                        x = A.getData("height");
                        this.nodeHelper.ellipse.render("fill", B, z, x, y)
                    },
                    contains: function(z, B) {
                        var y = z.getData("width"),
                        x = z.getData("height"),
                        A = z.pos.getc().$scale(z.scale);
                        return this.nodeHelper.circle.contains(A, B, y, x)
                    }
                },
                square: {
                    render: function(z, x) {
                        var y = this.node,
                        B = z.getData("dim"),
                        A = z.pos.getc();
                        B = y.transform ? B * (1 - A.squaredNorm()) : B;
                        A.$scale(z.scale);
                        if (B > 0.2) {
                            this.nodeHelper.square.render("fill", A, B, x)
                        }
                    },
                    contains: function(x, A) {
                        var y = x.getData("dim"),
                        z = x.pos.getc().$scale(x.scale);
                        return this.nodeHelper.square.contains(z, A, y)
                    }
                },
                rectangle: {
                    render: function(B, y) {
                        var A = this.node,
                        z = B.getData("width"),
                        x = B.getData("height"),
                        C = B.pos.getc();
                        z = A.transform ? z * (1 - C.squaredNorm()) : z;
                        x = A.transform ? x * (1 - C.squaredNorm()) : x;
                        C.$scale(B.scale);
                        if (z > 0.2 && x > 0.2) {
                            this.nodeHelper.rectangle.render("fill", C, z, x, y)
                        }
                    },
                    contains: function(z, B) {
                        var y = z.getData("width"),
                        x = z.getData("height"),
                        A = z.pos.getc().$scale(z.scale);
                        return this.nodeHelper.square.contains(A, B, y, x)
                    }
                },
                triangle: {
                    render: function(z, x) {
                        var y = this.node,
                        B = z.getData("dim"),
                        A = z.pos.getc();
                        B = y.transform ? B * (1 - A.squaredNorm()) : B;
                        A.$scale(z.scale);
                        if (B > 0.2) {
                            this.nodeHelper.triangle.render("fill", A, B, x)
                        }
                    },
                    contains: function(x, A) {
                        var y = x.getData("dim"),
                        z = x.pos.getc().$scale(x.scale);
                        return this.nodeHelper.triangle.contains(z, A, y)
                    }
                },
                star: {
                    render: function(z, x) {
                        var y = this.node,
                        B = z.getData("dim"),
                        A = z.pos.getc();
                        B = y.transform ? B * (1 - A.squaredNorm()) : B;
                        A.$scale(z.scale);
                        if (B > 0.2) {
                            this.nodeHelper.star.render("fill", A, B, x)
                        }
                    },
                    contains: function(x, A) {
                        var y = x.getData("dim"),
                        z = x.pos.getc().$scale(x.scale);
                        return this.nodeHelper.star.contains(z, A, y)
                    }
                }
            });
            w.Plot.EdgeTypes = new q({
                none: c.empty,
                line: {
                    render: function(x, y) {
                        var B = x.nodeFrom.pos.getc(true),
                        A = x.nodeTo.pos.getc(true),
                        z = x.nodeFrom.scale;
                        this.edgeHelper.line.render({
                            x: B.x * z,
                            y: B.y * z
                        },
                        {
                            x: A.x * z,
                            y: A.y * z
                        },
                        y)
                    },
                    contains: function(x, B) {
                        var A = x.nodeFrom.pos.getc(true),
                        z = x.nodeTo.pos.getc(true),
                        y = x.nodeFrom.scale;
                        this.edgeHelper.line.contains({
                            x: A.x * y,
                            y: A.y * y
                        },
                        {
                            x: z.x * y,
                            y: z.y * y
                        },
                        B, this.edge.epsilon)
                    }
                },
                arrow: {
                    render: function(y, z) {
                        var E = y.nodeFrom.pos.getc(true),
                        D = y.nodeTo.pos.getc(true),
                        A = y.nodeFrom.scale,
                        C = y.getData("dim"),
                        B = y.data.$direction,
                        x = (B && B.length > 1 && B[0] != y.nodeFrom.id);
                        this.edgeHelper.arrow.render({
                            x: E.x * A,
                            y: E.y * A
                        },
                        {
                            x: D.x * A,
                            y: D.y * A
                        },
                        C, x, z)
                    },
                    contains: function(x, B) {
                        var A = x.nodeFrom.pos.getc(true),
                        z = x.nodeTo.pos.getc(true),
                        y = x.nodeFrom.scale;
                        this.edgeHelper.arrow.contains({
                            x: A.x * y,
                            y: A.y * y
                        },
                        {
                            x: z.x * y,
                            y: z.y * y
                        },
                        B, this.edge.epsilon)
                    }
                },
                hyperline: {
                    render: function(x, y) {
                        var B = x.nodeFrom.pos.getc(),
                        A = x.nodeTo.pos.getc(),
                        z = this.viz.getRadius();
                        this.edgeHelper.hyperline.render(B, A, z, y)
                    },
                    contains: c.lambda(false)
                }
            })
        })($jit.Hypertree)
    })();